espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.31k stars 7.35k 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

mickeypop commented 6 years ago

@AIWIndustries

There is a way to look up a lockup if the Traceback is printed to the terminal.

Install "ESP Exception Decoder" from; https://github.com/me-no-dev/EspExceptionDecoder Instructions are there.

Once installed just copy and paste the traceback line and it will tell you what is happening at lock up.

seyyung1994 commented 6 years ago

Hi All,

The following code is working for me.

void wifiReconnect() { while (WiFi.status() != WL_CONNECTED) { WiFi.begin(ssid, password); for(int i=0; i<=50; i++) { digitalWrite(LED_BUILTIN, HIGH); delay(100); Serial.print("."); digitalWrite(LED_BUILTIN, LOW); delay(100); } } }

Use this in the loop() as

if (WiFi.status() != WL_CONNECTED) { wifiReconnect(); }

jjassar commented 6 years ago

Hi All I was using ESP32 core updated around 2 months ago. In my program i use Wifi.begin(ssid, pass) in setup() and calling WiFi.reconnect() method on "SYSTEM_EVENT_STA_DISCONNECTED" event. The system was connecting automatically if there are any disconnection. But yesterday i updated to latest core and that started giving error with reason code 8. After some hit and trials, i have commented WiFi.reconnect() then it started working perfectly. Also wifi reconnects automatically if AP is switched off and on.

In my case only in setup method i am using WiFi.mode(WIFI_STA); Wifi.begin()

this is working properly. Can we say that in new core there is no need to call reconnect() and autoreconnect is now working in latest core?

me-no-dev commented 6 years ago

correct. there is no need to call reconnect anymore ;) I have that fixed :P

mickeypop commented 6 years ago

There is a serious flaw in wifi.Reconnect().

In a deep look thru the libraries I found in several conditions it will connect without doing a DHCP update so you are connected without an IP address. -- I reported it but have not seen a fix yet.

I proved this once buy adding a UDP call in some test code. - I could talk to the AP by UDP but had no IP address. At the same time the MAC showed up on the AP connection list.

You want to use wifi.begin() it is always reliable. - You simply must be sure that you are down when calling it to connect or you could end up with stack overflow issues.

The template I wrote below has never failed to reconnect. It is uses SmartConfig and preferences instead of hard coding the AP/Pass though that could easily be changed.

Some of my code is proprietary to the LED flasher so i left comments in place instead. You can put any indicator code you want there.

Take a look at the wifi down part of loop(). I call WiFi.begin( PrefSSID.c_str() , PrefPassword.c_str() ); while always testing for a return status of WL_CONNECTED.

Hope this helps some.

// ESP32 only,  8266 will not work here
#include "FS.h"
#include "esp_system.h"
#include <esp_wifi.h>
#include <string.h>
#include <WiFi.h>
#include <Preferences.h> // WiFi storage

const char* rssiSSID;        // NO MORE hard coded set AP, all SmartConfig
const char* password;
String PrefSSID, PrefPassword;   // used by preferences storage

int WFstatus;
int UpCount; = 0;
int32_t rssi;         // store WiFi signal strength here
String getSsid;
String getPass;
String MAC;

// SSID storage
  Preferences preferences;       // declare class object
// END SSID storage

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

  Serial.printf("\tWiFi Setup -- \n" ); 
  wifiInit();      // get WiFi connected
  IP_info();
  MAC = getMacAddress();

  delay(2000);  // let thing settle
} // END setup()

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

         // ANY MAIN LOOP CODE HERE

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

    //  wifi down start LED flasher here

    WFstatus = getWifiStatus( WFstatus );
    WiFi.begin(  PrefSSID.c_str() , PrefPassword.c_str() );
    int WLcount = 0;
    while (  WiFi.status() != WL_CONNECTED && WLcount < 200 )
    {
      delay( 100 );
      Serial.printf(".");

        if (UpCount >= 60)  // keep from scrolling sideways forever
        {
           UpCount = 0;
           Serial.printf("\n");
        }
        ++UpCount;
        ++WLcount;
    }

    if( getWifiStatus( WFstatus ) == 3 )   //wifi returns
    { 
      // stop LED flasher, wifi going up
    }
   delay( 1000 );
  } // END WiFi down
} // END loop()

void wifiInit() //
{
  WiFi.mode(WIFI_AP_STA); // required to read NVR before WiFi.begin()

  // load credentials from NVR, a little RTOS code here
  wifi_config_t conf;
  esp_wifi_get_config(WIFI_IF_STA, &conf);     // load wifi settings to struct comf
  rssiSSID = reinterpret_cast<const char*>(conf.sta.ssid);
  password = reinterpret_cast<const char*>(conf.sta.password);

  //  Serial.printf( "SSID = %s\n", rssiSSID );  // un-comment for debuging
  //  Serial.printf( "Pass = %s\n", password );  // un-comment for debuging
  // Open Preferences with wifi namespace. Namespace is limited to 15 chars
  preferences.begin("wifi", false);
    PrefSSID     = preferences.getString("ssid", "none"); //NVS key ssid
    PrefPassword = preferences.getString("password", "none"); //NVS key password
  preferences.end();

  // keep from rewriting flash if not needed
  if( !checkPrefsStore() )   // see is NV and Prefs are the same
  {                          // not the same, setup with SmartConfig
    if( PrefSSID == "none" ) // New...setup wifi
    {
      initSmartConfig();
      delay( 3000);
      ESP.restart(); // reboot with wifi configured
    }
  }

  // I flash LEDs while connecting here

  WiFi.begin( PrefSSID.c_str() , PrefPassword.c_str() );

  int WLcount = 0;
  while (WiFi.status() != WL_CONNECTED && WLcount < 200 ) // can take > 100 loops depending on router settings
  {
    delay( 100 );
    Serial.printf(".");
    ++WLcount;
  }
  delay( 3000 );

  // stop the led flasher here

} // END wifiInit()

// match WiFi IDs in NVS to Pref store, assumes WiFi.mode(WIFI_AP_STA); was executed
bool checkPrefsStore()
{
  bool val = false;
  String NVssid, NVpass, prefssid, prefpass;

  NVssid = getSsidPass( "ssid" );
  NVpass = getSsidPass( "pass" );

  // Open Preferences with my-app namespace. Namespace name is limited to 15 chars
  preferences.begin("wifi", false);
    prefssid  =  preferences.getString("ssid",     "none"); //NVS key ssid
    prefpass  =  preferences.getString("password", "none"); //NVS key password
  preferences.end();

  if( NVssid.equals(prefssid) && NVpass.equals(prefpass) )
  { 
    val = true; 
  }
  return val;
} // END checkPrefsStore()

void initSmartConfig()
{
  // start LED flasher here
  int loopCounter = 0;

  WiFi.mode( WIFI_AP_STA );     //Init WiFi, start SmartConfig
  Serial.printf( "Entering SmartConfig\n" );

  WiFi.beginSmartConfig();

  while (!WiFi.smartConfigDone())
  { // flash led to indicate not configured
    Serial.printf( "." );
    if( loopCounter >= 40 )
    {
      loopCounter = 0;
      Serial.printf( "\n" );
    }
    delay(600);
    ++loopCounter;
  }
  loopCounter = 0;

  // stopped flasher here

  Serial.printf("\nSmartConfig received.\n Waiting for WiFi\n\n");
  delay(2000 );

  while( WiFi.status() != WL_CONNECTED )
  { // check till connected
     delay(500);
  }
  IP_info();

  preferences.begin("wifi", false); // put it in storage
    preferences.putString( "ssid" ,    getSsid);
    preferences.putString( "password", getPass);
  preferences.end();

  delay(300);
} // END SmartConfig()

void IP_info()
{
  getSsid = WiFi.SSID();
  getPass = WiFi.psk();
  rssi = getRSSI( rssiSSID );
  WFstatus = getWifiStatus( WFstatus );
  MAC = getMacAddress();

  Serial.printf( "\n\n\tSSID\t%s, ", getSsid.c_str() );
  Serial.print( rssi);  Serial.printf(" dBm\n" );  // printf??
  Serial.printf( "\tPass:\t %s\n", getPass.c_str() ); 
  Serial.print( "\n\n\tIP address:\t" );  Serial.print(WiFi.localIP() );
  Serial.print( " / " );              Serial.println( WiFi.subnetMask() );
  Serial.print( "\tGateway IP:\t" );  Serial.println( WiFi.gatewayIP() );
  Serial.print( "\t1st DNS:\t" );     Serial.println( WiFi.dnsIP() );
  Serial.printf( "\tMAC:\t\t%s\n", MAC.c_str() );
}  // END IP_info()

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

// Get the station interface MAC address.
// @return String MAC
String getMacAddress(void)
{
  WiFi.mode(WIFI_AP_STA); // required to read NVR before WiFi.begin()
  uint8_t baseMac[6];
  esp_read_mac( baseMac, ESP_MAC_WIFI_STA ); // Get MAC address for WiFi station
  char macStr[18] = { 0 };
  sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", baseMac[0], baseMac[1], baseMac[2], baseMac[3], baseMac[4], baseMac[5]);
  return String(macStr);
}  // END getMacAddress()

// Return RSSI or 0 if target SSID not found
// const char* SSID = "YOUR_SSID"; // declare in GLOBAL space
// call: int32_t rssi = getRSSI(SSID);
int32_t getRSSI( const char* target_ssid )
{
  byte available_networks = WiFi.scanNetworks();

  for (int network = 0; network < available_networks; network++)
  {
    if ( strcmp( WiFi.SSID( network).c_str(), target_ssid ) == 0)
    {
      return WiFi.RSSI( network );
    }
  }
  return 0;
} // END getRSSI()

// Requires; #include <esp_wifi.h>
// Returns String NONE, ssid or pass arcording to request
// ie String var = getSsidPass( "pass" );
String getSsidPass( String s )
{
  String val = "NONE"; // return "NONE" if wrong key sent
  s.toUpperCase();
  if( s.compareTo("SSID") == 0 )
  {
    wifi_config_t conf;
    esp_wifi_get_config( WIFI_IF_STA, &conf );
    val = String( reinterpret_cast<const char*>(conf.sta.ssid) );
  }
  if( s.compareTo("PASS") == 0 )
  {
    wifi_config_t conf;
    esp_wifi_get_config( WIFI_IF_STA, &conf );
    val = String( reinterpret_cast<const char*>(conf.sta.password) );
  }
  return val;
}  // END getSsidPass()
tablatronix commented 6 years ago

I noticed this as well, but never narrowed it down, But I noticed that reconnect() and begin(ssid..) does not always reset dhcp, edge case I think

Begin(args) only redoes dhcp if config is not equal or not already connected, else it returns, which might be a problem.

    wifi_config_t current_conf;
    esp_wifi_get_config(WIFI_IF_STA, &current_conf);
    if(!sta_config_equal(current_conf, conf)) {
        if(esp_wifi_disconnect()){
            log_e("disconnect failed!");
            return WL_CONNECT_FAILED;
        }

        esp_wifi_set_config(WIFI_IF_STA, &conf);
    } else if(status() == WL_CONNECTED){
        return WL_CONNECTED;
    }
 // We do not always get here
    if(!_useStaticIp) {
        if(tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA) == ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED){
            log_e("dhcp client start failed!");
            return WL_CONNECT_FAILED;
        }
    } else {
        tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
    }
jjassar commented 6 years ago

@mickeypop thanks for sharing code. But i have one doubt. As you said: I proved this once buy adding a UDP call in some test code. - I could talk to the AP by UDP but had no IP address. At the same time the MAC showed up on the AP connection list.

but as far i know, we can not make UDP connection without having an IP. UDP is built on IP layer.

mickeypop commented 6 years ago

@jjassar

UDP does not require any IP at all, just it's own MAC.

UDP is where the magic in the SmartConfig is. The app on your cell sends a specially formatted UDP packet just for the ESP32 with the AP credentials.

Because UDP is Connectionless, all WiFi devices on or off the AP can see it.

When the ESP32 sees this, it sends a different UDP to the AP to get a connection and the IP address from the AP. Remember before the connect there is no IP.

UDP is the under layer used in DHCP to get the IP in the first place but is also used in many other ways.

bedenko commented 6 years ago

@mickeypop is it possible, that you are mixing TCP/UDP with broadcast/multicast? TCP and UDP both reside on transport layer, which is build on top of internet layer, where IP is.

jjassar commented 6 years ago

@mickeypop @bedenko you both may be right, i think, it could be UDP broadcast on address 255.255.255.255. Anyway, i have found a new issue with latest repo. I was having an esp32 which was connected to AP, I switched off AP and Switched it back after some time. On disconnection if the reason code is 201(REASON_NO_AP_FOUND) then it connects automatically But sometimes the disconnection reason code 7(REASON_NOT_ASSOCED) then it never connects back, Only reconnect after hardware restart. Why reason code 7 is coming if I have switched off AP?

bedenko commented 6 years ago

Probably, because code 201 is resoved here, but code 7 is ignored.

mickeypop commented 6 years ago

@jjassar @bedenko

Think about it for a moment. There has to be a protocol to connect BEFORE the device has an IP otherwise DHCP would not have any means to contact the DHCP server to "Get" an IP.

I was a Network Engineer for over 30 years and if UDP was not an integral part of TCP/IP you would have to re-setup IPs every time you moved to another network.

here's a little primer.

DHCP PROTOCOL

DHCP protocol is a connectionless protocol using UDP Port 68 and 67. It operates on client & server model. The DHCP client is our device ( traveller ) and the DHCP server is the one who shall provide us the IP ( The innkeeper ).

DHCP operates on UDP because DHCP client works on broadcasts, which can only be supported by UDP. This is needed because the client machine has still not received an IP address (this is the DHCP negotiation protocol purpose) and there would not be any way to establish a TCP stream without the IP address itself.

DHCP client starts by broadcasting the DHCP DISCOVER packet. The broadcast is received by the DHCP Server(s), which in turn replies with the DHCP OFFER message. The DHCP OFFER message contains the IP address offered by the server and the time period for which the IP address is allocated (The IP may be random, or based on an admin policy).

The DHCP client may receive multiple DHCP OFFER messages, however it chooses only one DHCP OFFER message based on the policy configured in the DHCP Client. Usually its on the first come first serve basis. However we can configure the DHCP Client to choose the DHCP OFFER having the longest lease time or some preferred subnet. The DHCP client now replies with the DHCP REQUEST message.

The DHCP REQUEST message is a broadcast message. When other DHCP servers receive this message, they withdraw any offers that they might have made to the client and return the offered address to the pool of available addresses. The intended DHCP server on receiving the message sends a DHCP ACK message, thus confirming the transaction and allocating the IP to the host for the specified amount of time.

bedenko commented 6 years ago

@mickeypop: i agree with your explanation, except with the fact, that UDP can operate without IP address. All DHCP negotiation is done on broadcast IP 255.255.255.255 (info).

mickeypop commented 6 years ago

@bedenko You pretty much have to agree. I cut and pasted it directly from the official docs.

You are both right and wrong and here's why.

All network protocols use the same packet structure. AppleTalk, TCP/IP, Arpnet, AIX, etc... This let them coexist on the same ethernet without conflict.

The structure includes bits for protocol, type, checksum, destination etc... All look for the 24(255.255.255.255) bits in the destination identifier as a Special Identifier.

that said;

IP traffic is processed thru a Network Mask so all devices can determine if a packet is meant for them or not as well as routing.

UDP has no Network Mask. The 255.255.255.255 is not meant for the UDP sender or even used by them, it is so all other devices see the Special Identifier. It is not treated like an IP in this case at all.

NOTE: UDP sends by MAC not by IP.

Take DHCP for example, you don't have either IP or netmask yet, so the device goes into promiscuous mode looking for any packet with its own MAC address.

A DHCP DISCOVER packet is sent by UDP with the senders MAC address since the DHCP server must know who is requesting an IP.

The sender clearly cannot process it as IP traffic yet and to that end the DHCP server cannot use IP to send a response. Hence UDP.

The DHCP OFFER message returned by UDP must include the MAC for the client to know it is for them. Mind you all traffic is structured the same but it is not IP at all yet.

It is not until all negotiations are finished that any IP traffic is even possible.

===== Seperatly, i should note; I was on the team in 1968 - 70 developing the UNIX OS. There is where TCP/IP came to be. We used an early draft of UDP before TCP/IP even existed.

stickbreaker commented 6 years ago

@mickeypop Thanks for your work! We can all touch the Sky because we stand on the Shoulders of Giants!

Chuck.

ThiagoCas commented 6 years ago

Hi. I use this code for this

  if (WiFi.status() != WL_CONNECTED)
{
  digitalWrite(26,0);
  WIFI_Connect();
} else {
  digitalWrite(26,1);
}

and, this is te function "WIFI_Connect"

void WIFI_Connect() { digitalWrite(26,HIGH); WiFi.disconnect(); Serial.println("Reconectando WiFi..."); WiFi.mode(WIFI_AP_STA); WiFi.begin(ssid, password); // Wait for connection for (int i = 0; i < 50; i++) { if ( WiFi.status() != WL_CONNECTED ) { delay ( 500 ); digitalWrite(26,0); Serial.print ( "." ); delay ( 500 ); digitalWrite(26,1); } } digitalWrite(26,0); }

For me this code work. Obs: The version 2.3

ijaz1122 commented 6 years ago

include

include

define WIFI_SSID "===="

define WIFI_PASSWORD "==="

//this firebase project was deleted //you'll need to enter your own firebase info

define FIREBASE_HOST "home-automation-1122.firebaseio.com"

define FIREBASE_AUTH "============"

define LED1 5

define LED2 4

define LED3 0

define LED4 2

define LED5 14

define LED6 12

define LED7 13

define LED8 15

void setup() {

pinMode(LED1,OUTPUT);

digitalWrite(LED1,0);

pinMode(LED2,OUTPUT);

digitalWrite(LED2,0);

pinMode(LED3,OUTPUT);

digitalWrite(LED3,0);

pinMode(LED4,OUTPUT);

digitalWrite(LED4,0);

pinMode(LED5,OUTPUT);

digitalWrite(LED5,0);

pinMode(LED6,OUTPUT);

digitalWrite(LED6,0);

pinMode(LED7,OUTPUT);

digitalWrite(LED7,0);

pinMode(LED8,OUTPUT);

digitalWrite(LED8,0);

Serial.begin(9600);

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

Serial.print("connecting");

while (WiFi.status() != WL_CONNECTED) {

Serial.print(".");

delay(500);

}

Serial.println();

Serial.print("connected: ");

Serial.println(WiFi.localIP());

Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);

Firebase.setInt("LEDStatus",0);

}

void loop() {

if(Firebase.getInt("field1"))

{

digitalWrite(LED1,LOW);

}

else

{ digitalWrite(LED1,HIGH);

} if(Firebase.getInt("field2"))

{

digitalWrite(LED2,LOW);

}

else

{

digitalWrite(LED2,HIGH);

}

if(Firebase.getInt("field3"))

{

digitalWrite(LED3,LOW);

}

else

{ digitalWrite(LED3,HIGH);

}

if(Firebase.getInt("field4"))

{

digitalWrite(LED4,LOW);

}

else

{

digitalWrite(LED4,HIGH);

} if(Firebase.getInt("field5"))

{

digitalWrite(LED5,LOW);

}

else

{

digitalWrite(LED5,HIGH);

} if(Firebase.getInt("field6"))

{

digitalWrite(LED6,LOW);

}

else

{

digitalWrite(LED6,HIGH);

} if(Firebase.getInt("field7"))

{

digitalWrite(LED7,LOW);

}

else

{

digitalWrite(LED7,HIGH);

} if(Firebase.getInt("field8"))

{

digitalWrite(LED8,LOW);

}

else

{

digitalWrite(LED8,HIGH);

}

//Serial.println(Firebase.getInt("led1")); //Serial.println(Firebase.getInt("led2")); //Serial.println(Firebase.getInt("led3")); //Serial.println(Firebase.getInt("led4")); //Serial.println(Firebase.getInt("led5")); //Serial.println(Firebase.getInt("led6")); //Serial.println(Firebase.getInt("led7")); //Serial.println(Firebase.getInt("led8"));

Serial.println("..............."); if (Firebase.failed()) // Check for errors {

Serial.print("setting /number failed:");

Serial.println(Firebase.error());

return;

}

my nodemcu esp8226 not reconnect after connection lost til i re power it

bedenko commented 6 years ago

This thread is for esp32. Are u using esp8266, or was it a typo?

ijaz1122 commented 6 years ago

esp82255 nodemcu

On Tue, 11 Sep 2018 1:45 PM Bedenko, notifications@github.com wrote:

This thread is for esp32. Are u using esp8266, or was it a typo?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/espressif/arduino-esp32/issues/653#issuecomment-420196435, or mute the thread https://github.com/notifications/unsubscribe-auth/ApKpJ7SS4fk4KrHA1sVKmwV7brGVeh93ks5uZ3gxgaJpZM4PfOia .

ijaz1122 commented 6 years ago

Sorry this is esp8266

On Tue, 11 Sep 2018 1:48 PM Ijaz Ahmad, conceptualboy2@gmail.com wrote:

esp82255 nodemcu

On Tue, 11 Sep 2018 1:45 PM Bedenko, notifications@github.com wrote:

This thread is for esp32. Are u using esp8266, or was it a typo?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/espressif/arduino-esp32/issues/653#issuecomment-420196435, or mute the thread https://github.com/notifications/unsubscribe-auth/ApKpJ7SS4fk4KrHA1sVKmwV7brGVeh93ks5uZ3gxgaJpZM4PfOia .

ijaz1122 commented 6 years ago

anyone here help me?

vseven commented 6 years ago

This thread is for a ESP32, not a 8266. Try a different repo.

ijaz1122 commented 6 years ago

can u help me please with 8226

ijaz1122 commented 6 years ago

@vseven how can i solve this problem?

EBZ-Krisemendt commented 6 years ago

@ijaz1122 look here if there is any issue that suits your problem. otherwise open a new one over there. you currently asking for a solution on a different device. this is the wrong repo for your problem.

anuragkr16 commented 5 years ago

Hey all finally I get this code working to connect and reconnect my wifi/portable hotspot multiple times

Thanks to @ThiagoCas for his codes

`/**** Include Libraries ****/

include

/**** Define Constants ****/

define WIFISSID "==Your Wifi SSID==" // Put your WifiSSID here

define PASSWORD "==Your Password==" // Put your wifi password here

// constants won't change. Used here to set a pin number: const int ledPin = 2;// the number of the LED pin

/**** Define Variables ****/ // Variables will change: int ledState = LOW; // ledState used to set the LED

int interval = 100; // interval at which to blink (milliseconds)

// Generally, you should use "unsigned long" for variables that hold time // The value will quickly become too large for an int to store unsigned long previousMillis = 0; // will store last time LED was updated

/**** Auxiliar Functions ****/ void WIFI_Connect() { WiFi.disconnect(); Serial.println("Connecting to WiFi..."); WiFi.mode(WIFI_AP_STA); WiFi.begin(WIFISSID, PASSWORD);

for (int i = 0; i < 60; i++) { if ( WiFi.status() != WL_CONNECTED ) { delay ( 250 ); digitalWrite(ledPin, LOW); Serial.print ( "." ); delay ( 250 ); digitalWrite(ledPin, HIGH); } } if ( WiFi.status() == WL_CONNECTED ) { Serial.println(""); Serial.println("WiFi Connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } digitalWrite(ledPin, 0); }

/**** Main Functions ****/

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

// set the digital pin as output: pinMode(ledPin, OUTPUT); WIFI_Connect(); }

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

if (currentMillis - previousMillis >= interval) { if (WiFi.status() != WL_CONNECTED) { Serial.println("wifi disconnected "); WIFI_Connect(); } // save the last time you blinked the LED previousMillis = currentMillis; // if the LED is off turn it on and vice-versa: if (ledState == LOW) { ledState = HIGH; interval = 100; } else { ledState = LOW; interval = 2500; } // set the LED with the ledState of the variable: digitalWrite(ledPin, ledState); } }`

vseven commented 5 years ago

Newer firmware seems to help, gonna close this.

gdombiak commented 5 years ago

@vseven by newer firmware ... do you mean latest version from master of this library? I do not see new commits to master since Sep 26th so wonder if you are referring to something else.

Thanks for your clarification Gaston

vseven commented 5 years ago

I opened this over a year ago now so yes, newer as in the last couple months.

gdombiak commented 5 years ago

Great. Thanks for the clarification. I'm not sure when I updated last (2 months ago?) but I never saw this error after the last update (and it used to happen once every couple of months). I thought I was being lucky but I now see that it was more than luck. ;)

Great job. Gaston

rustyx commented 5 years ago

Also this seems to help:

    esp_wifi_set_ps(WIFI_PS_NONE);
maxdd commented 5 years ago

@vseven

Newer firmware seems to help, gonna close this.

Hello there, I always thought platformio by updating the arduino-esp32 library was also able to update what you called the firmware. Am i wrong? I'm still suffering from this problem!

Miq1 commented 5 years ago

@vseven Newer firmware seems to help, gonna close this.

Hello there, I always thought platformio by updating the arduino-esp32 library was also able to update what you called the firmware. Am i wrong? I'm still suffering from this problem!

Same here. Would like to have a pointer to how to update firmware by platformio to get around the disconnect issue myself...

mickeypop commented 5 years ago

@vseven Platform IO setup instructions and update are addressed here https://github.com/espressif/arduino-esp32/blob/master/docs/platformio.md

a tid bit however: on both Arduino and Platform IO when i use git to update the SDK i have on some occasions found the update was not complete and had issues.

Rename the esp32 folder and re-install from a fresh git and i have always gotten a clean update.
Just follow their instructions.

Miq1 commented 5 years ago

@mickeypop: well, my platformio is on the latest stable version, but I still have the disconnect issue. Do you suggest using the stage or upstream versions instead? The stable was only updated a few days ago, by the way.

liuzfesp commented 5 years ago

@Miq1 does this issue exist if only use IDF example?

Miq1 commented 5 years ago

I must confess that I am using the Arduino in Platformio environment only - I never dealt with the IDF. I will look into it today to see if I can set up a basic version of my application there.

Miq1 commented 5 years ago

Just for the records: I found that the workaround with disconnect() and subsequent begin() works for me if I do a mode(WIFI_OFF) and mode(WIFI_STA) in between. I am currently trying the reconnect 5 times in a row and would do an esp.restart() if all attempts failed, but so far no restart was necessary.

Miq1 commented 5 years ago

I observed a few restarts in the meantime, so the workaround seems not to be as effective.

bsayiner commented 4 years ago

Is there any update about this bug?

davydnorris commented 4 years ago

FWIW I see this often on ESP8266 units too - exact same symptoms. I've found I can change the connect quite drastically simply by orienting the unit differently - so it seems to be related to how the units (both ESP8266 and ESP32) respond to bad signal.

Given I am using NonOS and an ESP8266, the common denominator seems to be the low level networking below lwIP

mcpicoli commented 4 years ago

(Using 1.0.4 version of Arduino-esp32)

I had the same problem here (using ESP32). Found that rebooting the router solves the problem... once. That is, after the reboot, the ESP32 is able to connect to the AP, get an IP address and stay connected, but if something causes the connection to fail (like rebooting the ESP32), the ESP32 then is never able to connect to the AP again.

The router is a TP-Link TL-MR2030 that I keep around for wired ethernet tests and has firmware that is hopelessly outdated by years and no newer official firmware exists.

However, if I try to use other APs, like some quite new Ubiquiti units at the office, the problem simply does not happen at all. I even raised some suspicion on the IT staff by forcing the board to purposely reboot and reconnect repeatedly as fast as possible for hours on end... and no trouble at all.

So, in the end, while it is possible that something is wrong or incomplete in the ESP32's libraries, I am ready to put all the blame on the old router's firmware. Time to get a new router for tests, not from TP-LINK, however.

tablatronix commented 4 years ago

I usually suspect dns for things like this. Or sometimes the router still thinks you are connected and never allows you to reconnect

daald commented 4 years ago

No, the router is not to blame. At least in my case. Sure, it's not the newest (wnr2200) but with an up-to-date DD-WRT installed and several android, linux and windows devices working without issues.

To finally solve this issue for myself, I started over with a completely new implementation, based on WiFiClientEvents.ino - so it's event-based. I also read the newest commit messages of arduino-esp32 which revealed very recent but relevant commits. I had to do some debugging in WiFiGeneric.cpp and found that mode doesn't always do what's expected (https://github.com/espressif/arduino-esp32/issues/1306).

Final result: with a little patch on WiFiGeneric.cpp (see end of file), I was able to connect and disconnect several times to/from my AP - hurray :)

Let me know if you see something to improve.

/*
 * This is a very stable example of repeated connecting and disconnecting to/from a wifi access point on STA32
 * Unfortunately, it needs patching of the WiFiGeneric.cpp library file
 * Author: Daniel Alder, based on the example WiFiClientEvents.ino
 * Tested with Arduino 1.8.5 and 1.8.10 with ESP library from Nov 11 2019 (cec3fca4) + patch
*/

#include <WiFi.h>   

#include "HomeWifiConfig.h" // use an extra include or uncomment the following 2 lines
//const char* ssid     = "myssid"; // your network SSID (name of wifi network)
//const char* password = "****";   // your network password

typedef enum {
  MYSTATE_OFFLINE = 0,
  MYSTATE_CONNECTING,
  MYSTATE_ONLINE,
  MYSTATE_DISCONNECTING
} mystate_t;
mystate_t mystate = MYSTATE_OFFLINE;
long state_since = 0;

#define TIMEOUT_ONLINE     20  // reconnect after this [s] offline time
#define TIMEOUT_OFFLINE    20  // disconnect after this [s] online time
#define TIMEOUT_CONNECTING 20  // cancel connecting after this [s] without success

////////////////////////////////////////////////////////////////////////////////

long getUptime() {
  return esp_timer_get_time() / 1000000L;
}

void changeState(mystate_t state) {
  mystate = state;
  state_since = getUptime();
}

void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
{
    Serial.printf("[WiFi-event] event: %d\n", event);

    switch (event) {
        case SYSTEM_EVENT_WIFI_READY: 
            Serial.println("WiFi interface ready");
            break;
        case SYSTEM_EVENT_SCAN_DONE:
            Serial.println("Completed scan for access points");
            break;
        case SYSTEM_EVENT_STA_START:
            Serial.println("WiFi client started");
            break;
        case SYSTEM_EVENT_STA_STOP:
            Serial.println("WiFi client stopped");
            changeState(MYSTATE_OFFLINE);
            break;
        case SYSTEM_EVENT_STA_CONNECTED:
            Serial.println("Connected to access point");
            break;
        case SYSTEM_EVENT_STA_DISCONNECTED:
            Serial.println("Disconnected from WiFi access point");
            break;
        case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
            Serial.println("Authentication mode of access point has changed");
            break;
        case SYSTEM_EVENT_STA_GOT_IP:
            Serial.print("Obtained IP address: ");
            //Serial.println(WiFi.localIP());
            //Serial.println("WiFi connected");
            //Serial.print("IP address: ");
            Serial.println(IPAddress(info.got_ip.ip_info.ip.addr));

            changeState(MYSTATE_ONLINE);

            break;
        case SYSTEM_EVENT_STA_LOST_IP:
            Serial.println("Lost IP address and IP address is reset to 0");
            //changeState(MYSTATE_OFFLINE);
            break;
        case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
            Serial.println("WiFi Protected Setup (WPS): succeeded in enrollee mode");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_FAILED:
            Serial.println("WiFi Protected Setup (WPS): failed in enrollee mode");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
            Serial.println("WiFi Protected Setup (WPS): timeout in enrollee mode");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_PIN:
            Serial.println("WiFi Protected Setup (WPS): pin code in enrollee mode");
            break;
        case SYSTEM_EVENT_AP_START:
            Serial.println("WiFi access point started");
            break;
        case SYSTEM_EVENT_AP_STOP:
            Serial.println("WiFi access point  stopped");
            break;
        case SYSTEM_EVENT_AP_STACONNECTED:
            Serial.println("Client connected");
            break;
        case SYSTEM_EVENT_AP_STADISCONNECTED:
            Serial.println("Client disconnected");
            break;
        case SYSTEM_EVENT_AP_STAIPASSIGNED:
            Serial.println("Assigned IP address to client");
            break;
        case SYSTEM_EVENT_AP_PROBEREQRECVED:
            Serial.println("Received probe request");
            break;
        case SYSTEM_EVENT_GOT_IP6:
            Serial.println("IPv6 is preferred");
            break;
        case SYSTEM_EVENT_ETH_START:
            Serial.println("Ethernet started");
            break;
        case SYSTEM_EVENT_ETH_STOP:
            Serial.println("Ethernet stopped");
            break;
        case SYSTEM_EVENT_ETH_CONNECTED:
            Serial.println("Ethernet connected");
            break;
        case SYSTEM_EVENT_ETH_DISCONNECTED:
            Serial.println("Ethernet disconnected");
            break;
        case SYSTEM_EVENT_ETH_GOT_IP:
            Serial.println("Obtained IP address");
            break;
        default: break;
    }
}

#include "esp_wifi.h" // only for fixWifiPersistencyFlag()
/**
 * Disable persistent mode, see https://github.com/espressif/arduino-esp32/issues/1393
 */
void fixWifiPersistencyFlag() {
  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  Serial.printf("cfg.nvs_enable before: %d\n", cfg.nvs_enable);
  cfg.nvs_enable = 0;
}

////////////////////////////////////////////////////////////////////////////////

void setup()
{
  Serial.begin(115200);
  Serial.println("-----------------------------------------");
  Serial.println("THIS IS: newWifiImplementationUsingEvents");
  Serial.println("-----------------------------------------");

  WiFi.persistent(false);
  fixWifiPersistencyFlag();

  //Serial.setDebugOutput(true); 
  //WiFi.printDiag(Serial); 

  // delete old config
  WiFi.disconnect(true);

  state_since = getUptime();

  delay(1000);

  // warning: only the last defined event handler gets events!
  WiFi.onEvent(WiFiEvent);

  Serial.println("End of setup");
}

bool firstTime = true;

void loop()
{
  long uptime = getUptime();
  if (mystate == MYSTATE_ONLINE && state_since + TIMEOUT_ONLINE < uptime) {
    Serial.println("Disconnecting NOW");
    changeState(MYSTATE_DISCONNECTING);
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
  } else if (mystate == MYSTATE_OFFLINE && state_since+TIMEOUT_OFFLINE < uptime) {
    Serial.println("Connecting NOW");
    changeState(MYSTATE_CONNECTING);
    if (firstTime) {
      Serial.println("(firstTime)");
      WiFi.begin(ssid, password);
      firstTime = false;
    } else {
      // doesn't work without WiFiGeneric.cpp patch below
      WiFi.mode(WIFI_STA);
      WiFi.reconnect();
    }
  } else if (mystate == MYSTATE_CONNECTING && state_since+TIMEOUT_CONNECTING < uptime) {
    Serial.println("Cancelling NOW after no connect success");
    changeState(MYSTATE_DISCONNECTING);
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
  }

  delay(1000);
  if (uptime % 10 == 0) {
    Serial.printf("uptime %d\n", uptime);
  }
}

/* PATH FOR LIBRARY
diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp
index e562921..aab5805 100644
--- a/libraries/WiFi/src/WiFiGeneric.cpp
+++ b/libraries/WiFi/src/WiFiGeneric.cpp
@@ -483,8 +483,10 @@ void WiFiGenericClass::enableLongRange(bool enable)
 bool WiFiGenericClass::mode(wifi_mode_t m)
 {
     wifi_mode_t cm = getMode();
+    log_d("mode() cm=%d, m=%d", cm, m);
     if(cm == m) {
-        return true;
+        log_d("HACK: skip return true");
+        //return true;
     }
     if(!cm && m){
         if(!wifiLowLevelInit(_persistent)){
*/

/* ISSUES:
 *  
 * 1) The example WiFiClientEvents.ino says:
 * 
 *   WiFi.onEvent(WiFiEvent);
 *   WiFi.onEvent(WiFiGotIP, WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP);
 *   
 *   but the WiFiEvent function never receives a SYSTEM_EVENT_STA_GOT_IP!
 *   
 * 2) I used code from https://github.com/espressif/arduino-esp32/issues/1393 to fix the persistent config issue
 * 
 * 3) The list of events in WiFiClientEvents.ino (comment block) is missing an event. Same bug as fixed in 188560e7f33
 * 
 * 4) Without pathing of WiFiGeneric.cpp, the mode() function doesn't do anything anymore once WiFi it was initialized (not even connected)
 * 
 *   see also: https://github.com/espressif/arduino-esp32/issues/1306 (but the this patch is not yet mentioned there)
 * 
 * 5) just a note: there is a STA_LOST_IP event, 2 minutes after disconnecting. 
 *   So if you want to make your code stable, you should also test with TIMEOUT_OFFLINE > 130
 */
3h50 commented 4 years ago

Has anyone wiresharked this?

Had a similar issue with an arduino wifi rev 2 (different hardware, but issues negotiating between ap's and the device was eerily similar.)

https://github.com/arduino/nina-fw/issues/14

daald commented 4 years ago

@mrarmyant What do you expect to see using wireshark? I think we are talking about issues on OSI layers 1 and 2. Differently said: no SSID, no frequency, no packets

My code (above your post) runs stable since I posted it. But I don't think the problem is portable to something different than ESP* chips because it addresses issues of the ESP SDK, not Arduino

tablatronix commented 4 years ago

I blame issues like this on power supply

mickeypop commented 4 years ago

i wouldn't blame the PS, it's very unlikely unless you have a really weak supply this will not happen.

Wireshark is really useless here.

To understand you have to dig deep into the RTOS libraries where the real work is done, not the Arduino libs as they are a wrapper.

If you are using WiFi.reconnect() instead of WiFi.begin() you need to know a few things.

WiFi.begin() starts by setting all needed registers on the wifi chip and RTOS states before connecting, reconnect() does not. This was reported over 2 years ago.

WiFi.reconnect() often makes only half of the connection, establishing a chip level MAC connection with UDP but never making the TCP/IP connection as these are separate protocols. This is due to needed states not being preset by reconnect() it simply assumes they are there.
This is why some of you are not getting the SYSTEM_EVENT_STA_GOT_IP on reconnect.

Remember; reconnecting is needed because the states have already changed.

I ALWAYS reconnect with WiFi.begin() and have never failed.

====== as to a reset not connecting and saying there is already a connection you need to know DHCP. DHCP IP address is commonly re-established every 15 seconds.
Now let's say 2 second after reestablishing you press the reset.
The DHCP server isn't going to release the IP for another 13 seconds and on trying to connect it will report it in use.

A simple delay on boot before connecting has fixed this for me every time.
If you are setting up multiple other libraries, set them all first before WiFi.begin().

A good start timer will help here.
take a long var = millis(); in the first line of setup() and Serial.print( millis()-var); just before WiFi.begin() and find out just how fast you are actually booting. Then adjust accordingly.

I have been using the ESP32 for over 6 years and this has always worked.

mickeypop commented 4 years ago

UPDATE; i see a lot of WiFiEvent used and for debugging its good but to simply detect wifi down and reconnect the IF/ELSE below works reliably every time.

this works because it takes about 18 seconds from down to reporting WL_CONNECTED change, this gives the DHCP server time to release the IP for a reliable re connect later.

It has been working for over 6 years and counting.

loop()
{
  if ( WiFi.status() ==  WL_CONNECTED ) 
  {
    // WiFi is UP,  do what ever
  } else
  {
    // wifi down, reconnect here
   WiFi.begin(  );
    int WLcount = 0;
    while (WiFi.status() != WL_CONNECTED && WLcount < 200 ) 
    {
      delay( 100 );
         Serial.printf(".");
         if (UpCount >= 60)  // just keep terminal from scrolling sideways
         {
            UpCount = 0;
               Serial.printf("\n");
         }
         ++UpCount;
      ++WLcount;
    }
  }
} // END loop()

take a look at the skeleton code i posted on https://github.com/espressif/arduino-esp32/issues/1100

though it was for setup with SmartConfig it just works.

3h50 commented 4 years ago

@mrarmyant What do you expect to see using wireshark? I think we are talking about issues on OSI layers 1 and 2. Differently said: no SSID, no frequency, no packets

My code (above your post) runs stable since I posted it. But I don't think the problem is portable to something different than ESP* chips because it addresses issues of the ESP SDK, not Arduino

I wasn't referring really to arduino, but the wifi soc that is onboard that particular unit. It had issues with reconnect based on being hinky with dhcp. Someone reported that restarting their router fixed it, which is the problem we had (well restarting a windows dhcp server). There was an issue with the way it was acknowledging wether or not it had been disconnected. Just thought it might help with those issues up there, because neither unit would ever show as connected on the reconnects, and wireshark showed us why. Static IP's had no problem. It ended up being the wifi soc firmware that had to be fixed to handle the delay mentioned for DHCP issues. All of which were discovered via wireshark.