Hieromon / AutoConnect

An Arduino library for ESP8266/ESP32 WLAN configuration at runtime with the Web interface
https://hieromon.github.io/AutoConnect/
MIT License
902 stars 188 forks source link

AutoConnect Portal is not opening once router is restarted during the run-time. #121

Closed krutarthtrivedi closed 4 years ago

krutarthtrivedi commented 5 years ago

Hello Hieromon, Greetings!

Board: ESP32 Development Board IDE: Arduino

I am using Autoconnect library with STA static IP assignment configuration. Once ESP gets connected with my router, I am able to open Autoconnect portal using "staip" provided by me in configuration

. But if router is reset or power off and then getting power on, the Autoconnect portal is not getting open using "staip". Kindly look into this. Thanks.

Following is my configuration:

IPAddress local_IP(192, xxx, xx, 100);
IPAddress gateway(192, xxx, xx, 1);
IPAddress subnet(255, xxx, xxx, 0);
IPAddress DNS1(8, 8, 8, 8);
IPAddress DNS2(8, 8, 4, 4);

  Config.boundaryOffset = CREDENTIAL_OFFSET;
  Config.autoReconnect = true;
  Config.apid = "XYZ";
  Config.psk = "9876543210";
  Config.staip = local_IP;
  Config.staGateway = gateway;
  Config.staNetmask = subnet;
  Config.dns1 = DNS1;
  Config.dns2 = DNS2;
  Portal.config(Config);
krutarthtrivedi commented 5 years ago

Find the attached image for your reference:

Capture

Hieromon commented 5 years ago

Sorry for reply late. I prioritize support for arduino-esp32 1.0.3. So, I have not yet tried to reproduce posted issue. It doesn't seem to be an AutoConnect issue, but could you reproduce the issue with the Core Debug level set to "Debug"? Please post the debug message again.

krutarthtrivedi commented 5 years ago

Hello Hieromon,

Sorry for the late reply. Followings are the responses as per asked.

  1. On startup, ESP32 searched for WiFi and gets connected with the WiFi router using static credentials provided through AutoConnect config.

1

  1. After connection has been established, I opened ESP32 IP address inside a web browser and the Portal gets opened.

2

  1. Now I switched off the router and ESP32 shows the following output.

3

  1. ESP32 keeps searching for WiFi.

4

  1. Now I turned on the router and after some time, ESP32 gets automatically connected to the same WiFi router.

6

  1. Once ESP32 has been connected with WiFi router, I tried to reopen the ESP32 IP Address inside a web browser and it shows the following error.

5

Kindly look into this.

Thanks. Krutarth Trivedi.

Hieromon commented 5 years ago

@krutarthtrivedi Thank you for your reports. I cannot reproduce the issue yet. Here is my test log:

Connected ->12:10:28.535 -> [D][WiFiGeneric.cpp:381] _eventCallback(): STA IP: 172.20.10.4, MASK: 255.255.255.240, GW: 172.20.10.1
            12:10:28.535 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 7 - STA_GOT_IP
            12:10:28.569 -> [D][WiFiGeneric.cpp:381] _eventCallback(): STA IP: 172.20.10.4, MASK: 255.255.255.240, GW: 172.20.10.1
            12:10:28.807 -> [AC] WebServer allocated
            12:10:28.807 -> [AC] http server started
            ... Here, visited some pages
<Router stopped>
IP lost   ->12:12:38.788 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 5 - STA_DISCONNECTED
link lost ->12:12:38.822 -> [W][WiFiGeneric.cpp:353] _eventCallback(): Reason: 200 - BEACON_TIMEOUT
            12:12:38.822 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 0 - WIFI_READY
            12:12:38.856 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
            12:12:38.856 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
            12:12:40.905 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 5 - STA_DISCONNECTED
            12:12:40.905 -> [W][WiFiGeneric.cpp:353] _eventCallback(): Reason: 201 - NO_AP_FOUND
            12:12:40.905 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 0 - WIFI_READY
            ... SAME AS ABOVE
            13:00:42.076 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
            13:00:42.076 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
            13:00:44.116 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 5 - STA_DISCONNECTED
            13:00:44.116 -> [W][WiFiGeneric.cpp:353] _eventCallback(): Reason: 201 - NO_AP_FOUND
<Router restarted>
            13:00:44.116 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 0 - WIFI_READY
            13:00:44.150 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
            13:00:44.150 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 2 - STA_START
IP recv.  ->13:00:45.137 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 7 - STA_GOT_IP
            13:00:45.137 -> [D][WiFiGeneric.cpp:381] _eventCallback(): STA IP: 172.20.10.4, MASK: 255.255.255.240, GW: 172.20.10.1
            13:00:45.137 -> [D][WiFiGeneric.cpp:337] _eventCallback(): Event: 7 - STA_GOT_IP
            13:00:45.171 -> [D][WiFiGeneric.cpp:381] _eventCallback(): STA IP: 172.20.10.4, MASK: 255.255.255.240, GW: 172.20.10.1
/_ac res. ->13:01:13.950 -> [AC] Host:172.20.10.4,URI:/_ac,already allocated
            13:01:13.950 -> [AC] Host:172.20.10.4,URI:/_ac,already allocated
            13:01:13.983 -> [D][WiFiClient.cpp:509] connected(): Disconnected: RES: 0, ERR: 128

As you can see from the log, TCP connection recovered automatically even if WIFi disconnected about 50 minutes. Your case seems similar to the esp32 issue that remains unresolved. The issue implies that once the WiFi data link (IP) is recovered after the router restarts, but the TCP socket once closed will not reopen. However, I encountered a successful case during a reproduction test of this problem when I tested a cell phone with desalted as a router.

After restarting the router, does the esp32 respond when a ping is thrown after WiFi reconnected? If the esp32 module does not respond to the ping, TCP remains closed. It is also necessary to reconnect the client browser to the router after restarting.

If we may not clear the cause, I will consider improving the AutoConnect library as a workaround. The phenomenon of not automatically recovering after disconnected WiFi can be fatal to IoT devices. Also, the workaround will look like this:

krutarthtrivedi commented 5 years ago

@Hieromon Thanks for the workaround. Currently, I am using 0.9.11 release. I'll check the same using the latest release today and will share the results. Meanwhile, Can you please send me the arduino program, using which you performed the similar test. It would be beneficial for me to understand the problem better and I can produce some test result, if the same issue still arises.

Thanks, Krutarth Trivedi.

Hieromon commented 5 years ago

@krutarthtrivedi

Can you please send me the arduino program, using which you performed the similar test.

It is here and is one of the example sketches included in upcoming v1.0.0 very soon. https://github.com/Hieromon/AutoConnect/blob/Enhance/v099/examples/ConfigIP/ConfigIP.ino

So, Have you tried ping after reconnecting?

Hieromon commented 5 years ago

@krutarthtrivedi I released v1.0.0 which has amended Config.ino. Please, you use this one with AutoConnect v1.0.0 for the reproduction test. In ESP32 with AutoConnect v1.0.0, Saved credentials area has moved from EEPROM to Preferences. So, past saved credentials will be unreached. You will need to reconnect again using a captive portal at least once.

krutarthtrivedi commented 5 years ago

@krutarthtrivedi

Can you please send me the arduino program, using which you performed the similar test.

It is here and is one of the example sketches included in upcoming v1.0.0 very soon. https://github.com/Hieromon/AutoConnect/blob/Enhance/v099/examples/ConfigIP/ConfigIP.ino

So, Have you tried ping after reconnecting?

As instructed, I have started testing the same using v1.0.0 and ESP32 1.0.2 SDK. I am unaware of how to use ping command. Please guide me through this. So, I can try to give a ping from ESP32.

Besides, I tried pinging using cmd command after router reboot and this is what i got. First Ping request is of before router reboot and the preceding one is of after router reboot.

7

Thanks, Krutarth Trivedi.

Hieromon commented 5 years ago

@krutarthtrivedi It has become clear what is happening. TCP remains closed after the WiFi data link has established again after the router restarts. Can you try something more test before I implement the workaround? because I cannot reproduce the issue. Please try as following procedure:

Even with the above patch applied, if the same problem occurs, you need to implement a more complex restore sequence in the event handler. It is a workaround that I may implement by AutoConnect.

krutarthtrivedi commented 5 years ago

@Hieromon I tried as per instructed, no luck!!! Tried with different routers as well but nothing worked for me. I can't even see any ping event taking place for me!

This is the Debug log I got. I found none changes in this using v1.0.0. WiFi is showing WiFi_Connected() event but actual TCP connection is not being established.

[W][WiFiGeneric.cpp:351] _eventCallback(): Reason: 201 - NO_AP_FOUND [D][WiFiGeneric.cpp:336] _eventCallback(): Event: 0 - WIFI_READY [D][WiFiGeneric.cpp:336] _eventCallback(): Event: 2 - STA_START [D][WiFiGeneric.cpp:336] _eventCallback(): Event: 2 - STA_START [D][WiFiGeneric.cpp:336] _eventCallback(): Event: 7 - STA_GOT_IP [D][WiFiGeneric.cpp:379] _eventCallback(): STA IP: 192.168.31.100, MASK: 255.255.255.0, GW: 192.168.31.1 [D][WiFiGeneric.cpp:336] _eventCallback(): Event: 7 - STA_GOT_IP [D][WiFiGeneric.cpp:379] _eventCallback(): STA IP: 192.168.31.100, MASK: 255.255.255.0, GW: 192.168.31.1

If you have a cell phone that can be dithered, use it as a router for a similar test too.

Does that mean using a mobile hotspot and perform the test?

Please look into this matter as I am in the middle of the development phase and got stuck in this.

Thanks, Krutarth Trivedi.

krutarthtrivedi commented 5 years ago

@Hieromon I tried HTTP GET request to google.com, just to replicate ping feature. Here's the code.

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  AutoConnectConfig Config;

  Config.boundaryOffset = CREDENTIAL_OFFSET;

  Config.hostName = "XXX";
  Config.staip = local_IP;
  Config.staGateway = gateway;
  Config.staNetmask = subnet;
  Config.dns1 = DNS1;
  Config.dns2 = DNS2;

  Portal.config(Config);

  if (Portal.begin()) {
    Serial.println("WiFi connected: " + WiFi.localIP().toString());
    delay(3000);
  }
}

void testClient(const char * host, uint16_t port)
{
  Serial.print("\nconnecting to ");
  Serial.println(host);

  WiFiClient client;
  if (!client.connect(host, port)) {
    Serial.println("connection failed");
    return;
  }
  client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
  while (client.connected() && !client.available());
  while (client.available()) {
    Serial.write(client.read());
  }

  Serial.println("closing connection\n");
  client.stop();
}

void loop() {
  Portal.handleClient();

  wifi_status = WiFi.status();

  if(wifi_status == WL_CONNECTED)
  {
    testClient("google.com", 80);
  }

  else
  {
    Serial.println("No WiFi connection");
  }
  delay(5000);
}

On startup, I got connection established to "google.com" and got the GET response. Besides, ping to ESP32 from computer connected in the same network works fine. Here's the screenshot of the same.

8

After router reset, ESP32 is automatically connected with Router but couldn't establish connection with "google.com" and presents the error shown in the following figure.

9

Everything works good after resetting ESP32. So, I think this is something related to TCP/IP connection reestablishment or socket reopen but I am not sure at this point of time.

Kindly look into this.

Thanks, Krutarth Trivedi.

Hieromon commented 5 years ago

@krutarthtrivedi

I think this is something related to TCP/IP connection reestablishment or socket reopen but I am not sure at this point of time.

As I said https://github.com/Hieromon/AutoConnect/issues/121#issuecomment-529380940, Your case is a known issue with ESP32. You can easily find that many developers are discussing the similar issues in the arduino-esp32 repository, but no stable solution find yet. As a matter of fact, the arduino-esp32 core already implements connection restoration as a measure against WiFi disconnection as follows: https://github.com/espressif/arduino-esp32/blob/bab3a70f543dac8f131916fcfc24b99b6b8252a0/libraries/WiFi/src/WiFiGeneric.cpp#L351-#L372 And we can see your log that the IP link has re-established as a result of above logic running. The problem is that even if it executes WiFi.disconnect & WiFi.begin, the TCP connection between the router may not recover actually. https://github.com/espressif/arduino-esp32/issues/1879 https://community.openmqttgateway.com/t/esp32-doesnt-stay-online/570/56?u=1technophile

As the issue can not be reproduced my environment yet, from the results of our verification so far, I think that other strategies for reconnection is necessary, more tests are needed.

Does that mean using a mobile hotspot and perform the test?

Yes, use a smartphone as a mobile hotspot and test with a simple sketch of WiFi.begin and http GET loop without AutoConnect as follows. It works fine in my environment with my ESP32 module which supplied with sufficient current > 2A.

Although it is unlikely that the cause of the problem is AutoConnect, the test sketch does not use AutoConnect to determine the cause and includes reconnection logic triggered by the STA_DISCONNECTED event. If you use this test code and you encounter similar problems, the effective workaround is to reset the module by counting the number of STA_DISCONNECTED events, for now.

Restriction

  1. Needs patch to arduino-esp32 core Current arduino-esp32 core (1.0.3 rc-3 earlier) needs a patch to receive STA_DISCONNECTED event correctly. https://github.com/espressif/arduino-esp32/pull/3085 https://github.com/espressif/arduino-esp32/commit/cd4f9038eecd0cc7c314c84fdca3d4bcb1515c12 https://github.com/espressif/arduino-esp32/blob/07390157dfd968ad79449af1d98a2406302c8c33/libraries/WiFi/src/WiFiGeneric.cpp#L370 Before you test, you need to modify WiFiGenetic.cpp of arduino-esp32 core source code the above.

  2. Compile with Core Debug Level:Info or lower To catch WiFi events with a sketch correctly, Core debug level at compile must be Info or lower.

Test sketch with reconnection

#include <WiFi.h>

#define SSID     "YOUR_SSID"
#define PASSWORD "YPUR_PASSWORD"

IPAddress local_IP(xxx, xxxx, xxx, xxx);
IPAddress gateway(xxx, xxxx, xxx, xxx);
IPAddress subnet(xxx, xxxx, xxx, xxx);
IPAddress DNS1(xxx, xxxx, xxx, xxx);
IPAddress DNS2(xxx, xxxx, xxx, xxx);
wifi_event_id_t eventDiscon;
wifi_event_id_t eventGotIP;
wifi_event_id_t eventRescon;
bool staDiscon;
bool staGotIP;
bool rip;
unsigned long tmDiscon;

void cbDiscon(WiFiEvent_t e, WiFiEventInfo_t info) {
  Serial.println("[E] SYSTEM_EVENT_STA_DISCONNECTED");
  staDiscon = true;
  tmDiscon = millis();
}

void cbGotIP(WiFiEvent_t e, WiFiEventInfo_t info) {
  Serial.println("[E] SYSTEM_EVENT_STA_GOT_IP");
  staGotIP = true;
}

void onDiscon(void) {
  staDiscon = false;
  staGotIP = false;
  rip = false;
  eventDiscon = WiFi.onEvent(cbDiscon, SYSTEM_EVENT_STA_DISCONNECTED);
  eventGotIP = WiFi.onEvent(cbGotIP, SYSTEM_EVENT_STA_GOT_IP);
}

void removeEvent(void) {
  staDiscon = false;
  staGotIP = false;
  WiFi.removeEvent(eventDiscon);
  WiFi.removeEvent(eventGotIP);
}

void cbRescon(WiFiEvent_t e, WiFiEventInfo_t info) {
  Serial.println("[E] Connecttion restored");
  WiFi.removeEvent(eventRescon);
  onDiscon();
}

void restoreIP(unsigned long tmWhile) {
  if (!rip) {
    if (staDiscon & staGotIP) {
      if (millis() - tmDiscon > tmWhile) {
        rip = true;
        removeEvent();
        WiFi.reconnect();
        eventRescon = WiFi.onEvent(cbRescon, SYSTEM_EVENT_STA_GOT_IP);
      }
    }
  }
}

wl_status_t connectWiFi(const unsigned long timeout) {
  wl_status_t st;
  Serial.print("Connecting");
  // WiFi.begin(SSID, PASSWORD);
  WiFi.begin();
  unsigned long tm = millis();
  while ((st = WiFi.status()) != WL_CONNECTED) {
    if (millis() - tm > timeout)
      break;
    Serial.print('.');
    delay(300);
  }
  return st;
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();

  WiFi.softAPdisconnect(true);
  WiFi.mode(WIFI_STA);
  delay(100);
  WiFi.setHostname("XXX");
  if (!WiFi.config(local_IP, gateway, subnet, DNS1, DNS2)) {
    Serial.println("WiFi.config failed");
    return;
  }
  if (connectWiFi(30000) == WL_CONNECTED) {
    Serial.println("connected:" + WiFi.localIP().toString());
    onDiscon();
  }
  else
    Serial.println("timeout");
  delay(3000);
}

void testClient(const char * host, uint16_t port) {
  Serial.print("\nconnecting to ");
  Serial.println(host);

  WiFiClient client;
  if (!client.connect(host, port)) {
    Serial.println("connection failed");
    return;
  }
  client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
  while (client.connected() && !client.available());
  while (client.available()) {
    Serial.write(client.read());
  }

  Serial.println("closing connection\n");
  client.stop();
}

void loop() {
  wl_status_t wifi_status = WiFi.status();

  if (wifi_status == WL_CONNECTED) {
    testClient("google.com", 80);
  }
  else
    Serial.println("No WiFi connection");

  restoreIP(5000);

  delay(5000);
}

Test sketch without reconnection

If you succeed with the above code, test one more thing. The following code does not include connection recovery by event trigger. It delegates the reconnection task to the arduino-esp32 core. If you encounter the same problem as a result of the change, the event-triggered recovery method is in effect.

#include <WiFi.h>

#define SSID     "YOUR_SSID"
#define PASSWORD "YPUR_PASSWORD"

IPAddress local_IP(xxx, xxxx, xxx, xxx);
IPAddress gateway(xxx, xxxx, xxx, xxx);
IPAddress subnet(xxx, xxxx, xxx, xxx);
IPAddress DNS1(xxx, xxxx, xxx, xxx);
IPAddress DNS2(xxx, xxxx, xxx, xxx);

wl_status_t connectWiFi(const unsigned long timeout) {
  wl_status_t st;
  Serial.print("Connecting");
  // WiFi.begin(SSID, PASSWORD);
  WiFi.begin();
  unsigned long tm = millis();
  while ((st = WiFi.status()) != WL_CONNECTED) {
    if (millis() - tm > timeout)
      break;
    Serial.print('.');
    delay(300);
  }
  return st;
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();

  WiFi.softAPdisconnect(true);
  WiFi.mode(WIFI_STA);
  delay(100);
  WiFi.setHostname("XXX");
  if (!WiFi.config(local_IP, gateway, subnet, DNS1, DNS2)) {
    Serial.println("WiFi.config failed");
    return;
  }
  if (connectWiFi(30000) == WL_CONNECTED) {
    Serial.println("connected:" + WiFi.localIP().toString());
  }
  else
    Serial.println("timeout");
  delay(3000);
}

void testClient(const char * host, uint16_t port) {
  Serial.print("\nconnecting to ");
  Serial.println(host);

  WiFiClient client;
  if (!client.connect(host, port)) {
    Serial.println("connection failed");
    return;
  }
  client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
  while (client.connected() && !client.available());
  while (client.available()) {
    Serial.write(client.read());
  }

  Serial.println("closing connection\n");
  client.stop();
}

void loop() {
  wl_status_t wifi_status = WiFi.status();

  if (wifi_status == WL_CONNECTED) {
    testClient("google.com", 80);
  }
  else
    Serial.println("No WiFi connection");
  delay(5000);
}
krutarthtrivedi commented 5 years ago

@Hieromon

ESP32 Repository: 1.0.3-rc3 The suggested changes for WiFi.disconnect() has been performed.

Test sketch with reconnection is working as expected like after re-establishment of WiFi connection, first GET request is showing ERROR but after that connection is restored and GET request is working good.

No WiFi connection [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_DISCONNECTED No WiFi connection [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_DISCONNECTED No WiFi connection [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_DISCONNECTED No WiFi connection [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_DISCONNECTED No WiFi connection [E] SYSTEM_EVENT_STA_DISCONNECTED [E] SYSTEM_EVENT_STA_GOT_IP [E] SYSTEM_EVENT_STA_GOT_IP

connecting to 172.217.27.174 connection failed [E] Connecttion restored [E] SYSTEM_EVENT_STA_GOT_IP [E] SYSTEM_EVENT_STA_GOT_IP

connecting to 172.217.27.174 HTTP/1.1 301 Moved Permanently Location: http://www.google.com/ Content-Type: text/html; charset=UTF-8 Date: Fri, 13 Sep 2019 09:23:57 GMT Expires: Sun, 13 Oct 2019 09:23:57 GMT Cache-Control: public, max-age=2592000 Server: gws Content-Length: 219 X-XSS-Protection: 0 X-Frame-Options: SAMEORIGIN

301 Moved

301 Moved

The document has moved here.

closing connection

Test sketch without reconnection is still showing the same socket error.

Now, What's your view on this?

Thanks, Krutarth Trivedi.

Hieromon commented 5 years ago

@krutarthtrivedi Thank you for the result report. It's kind of deeply rooted and tricky. It seems to me that the root of the causes is in the lwIP, not the arduino core. Anyway, I will post an issue to the arduino-esp32 core repository. We may get some hints from the contributors.

krutarthtrivedi commented 5 years ago

@Hieromon Thanks a lot for your support! Let's wait for the contributors to reply. So, I can plan accordingly for my ongoing development.

Thanks, Krutarth Trivedi.

Hieromon commented 5 years ago

You can work around this problem in your development project diverting "Test sketch with reconnection" as above like as:

#include <WiFi.h>
#include <WebServer.h>
#include <AutoConnect.h>

IPAddress local_IP(xxx, xxxx, xxx, xxx);
IPAddress gateway(xxx, xxxx, xxx, xxx);
IPAddress subnet(xxx, xxxx, xxx, xxx);
IPAddress DNS1(xxx, xxxx, xxx, xxx);
IPAddress DNS2(xxx, xxxx, xxx, xxx);

wifi_event_id_t eventDiscon;
wifi_event_id_t eventGotIP;
wifi_event_id_t eventRescon;
bool staDiscon;
bool staGotIP;
bool rip;
unsigned long tmDiscon;
unsigned long tmPeriod;

AutoConnect portal;
AutoConnectConfig config;

void cbDiscon(WiFiEvent_t e, WiFiEventInfo_t info) {
  Serial.println("[E] SYSTEM_EVENT_STA_DISCONNECTED");
  staDiscon = true;
  tmDiscon = millis();
}

void cbGotIP(WiFiEvent_t e, WiFiEventInfo_t info) {
  Serial.println("[E] SYSTEM_EVENT_STA_GOT_IP");
  staGotIP = true;
}

void onDiscon(void) {
  staDiscon = false;
  staGotIP = false;
  rip = false;
  eventDiscon = WiFi.onEvent(cbDiscon, SYSTEM_EVENT_STA_DISCONNECTED);
  eventGotIP = WiFi.onEvent(cbGotIP, SYSTEM_EVENT_STA_GOT_IP);
}

void removeEvent(void) {
  staDiscon = false;
  staGotIP = false;
  WiFi.removeEvent(eventDiscon);
  WiFi.removeEvent(eventGotIP);
}

void cbRescon(WiFiEvent_t e, WiFiEventInfo_t info) {
  Serial.println("[E] Connection restored");
  WiFi.removeEvent(eventRescon);
  onDiscon();
}

void restoreIP(unsigned long tmWhile) {
  if (!rip) {
    if (staDiscon & staGotIP) {
      if (millis() - tmDiscon > tmWhile) {
        rip = true;
        removeEvent();
        WiFi.reconnect();
        eventRescon = WiFi.onEvent(cbRescon, SYSTEM_EVENT_STA_GOT_IP);
      }
    }
  }
}

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();

  config.staip = local_IP;
  config.staGateway = gateway;
  config.staNetmask = subnet;
  config.dns1 = DNS1;
  config.dns2 = DNS2;

  portal.config(config);
  if (portal.begin()) {
    Serial.println("connected:" + WiFi.localIP().toString());
    onDiscon();
  }
  delay(3000);
  tmPeriod = millis();
}

void testClient(const char * host, uint16_t port) {
  Serial.print("\nconnecting to ");
  Serial.println(host);

  WiFiClient client;
  if (!client.connect(host, port)) {
    Serial.println("connection failed");
    return;
  }
  client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
  while (client.connected() && !client.available());
  while (client.available()) {
    Serial.write(client.read());
  }

  Serial.println("closing connection\n");
  client.stop();
}

void loop() {
  if (millis() - tmPeriod > 5000) {
    tmPeriod = millis();
    wl_status_t wifi_status = WiFi.status();
    if (wifi_status == WL_CONNECTED)
      testClient("google.com", 80);
    else
      Serial.println("No WiFi connection");
  }
  restoreIP(5000);
  portal.handleClient();
}

However, this code is risky a little. Even if the arduino-core reconnect completes successfully, the reconnect attempt is performed twice. This is a detrimental effect of returning WL_CONNECTED with WiFi.status even if TCP is still closed.

krutarthtrivedi commented 5 years ago

@Hieromon Okay, I will workaround on this and will let you know if I found any solution for this. Meanwhile, Let's hear from the contributors first.

Thanks, Krutarth Trivedi.

Hieromon commented 4 years ago

Close once due to no activity record for one month. Reopen when new reports are posted.