WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
User avatar
ghawkins
Posts: 5
Joined: Wed Mar 11, 2020 10:00 pm
Location: Zurich, Switzerland
Contact:

WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

Post by ghawkins » Wed Mar 11, 2020 10:26 pm

I thought I would be able to use WLAN.status() to detect if the wrong password was specified when connecting to a given SSID.

However, it just continuously reports STAT_CONNECTING and it's only in the log output that I see that something is wrong - I continuously see:

Code: Select all

I (101375) wifi: STA_DISCONNECTED, reason:15
I (103435) wifi: STA_DISCONNECTED, reason:205
If you call WLAN.connect(ssid, password) it tries repeatedly to connect, is there no way to detect that the connections are failing because the password is incorrect, i.e. how would I ever see STAT_WRONG_PASSWORD?

The following example demonstrates the issue:

Code: Select all

import network

ssid = "George Hawkins AC"
password = "My incorrect password"

sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.connect(ssid, password)

status = -1
while not sta.isconnected():
    new_status = sta.status()
    if new_status != status:
        status = new_status
        print('Status', status)

print("Connected to {} with address {}".format(ssid, sta.ifconfig()[0]))
Just replace the SSID with the name of your WiFi network (and deliberately leave password with an incorrect value) and run the program. You'll see that status never changes from STAT_CONNECTING.

Here's the complete output from my REPL session:

Code: Select all

>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== import network
=== 
=== ssid = "George Hawkins AC"
=== password = "My incorrect password"
=== 
=== sta = network.WLAN(network.STA_IF)
=== sta.active(True)
=== sta.connect(ssid, password)
=== 
=== status = -1
=== while not sta.isconnected():
===     new_status = sta.status()
===     if new_status != status:
===         status = new_status
===         print('Status', status)
=== 
=== print("Connected to {} with address {}".format(ssid, sta.ifconfig()[0]))
I (68420) wifi: wifi driver task: 3ffd2bcc, prio:23, stack:3584, core=0
I (83795) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (83805) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (83825) wifi: wifi firmware version: 10f4364
I (83825) wifi: config NVS flash: enabled
I (83825) wifi: config nano formating: disabled
I (83835) wifi: Init dynamic tx buffer num: 32
I (83835) wifi: Init data frame dynamic rx buffer num: 32
I (83845) wifi: Init management frame dynamic rx buffer num: 32
I (83845) wifi: Init management short buffer num: 32
I (83855) wifi: Init static rx buffer size: 1600
I (83855) wifi: Init static rx buffer num: 10
I (83855) wifi: Init dynamic rx buffer num: 32
I (83955) phy: phy_version: 4102, 2fa7a43, Jul 15 2019, 13:06:06, 0, 0
I (83955) wifi: mode : sta (a4:cf:12:62:12:24)
True
I (83955) wifi: STA_START
Status 1001
I (84085) wifi: new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (84925) wifi: state: init -> auth (b0)
I (84935) wifi: state: auth -> assoc (0)
I (84945) wifi: state: assoc -> run (10)
I (88955) wifi: state: run -> init (2c0)
I (88955) wifi: new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (88955) wifi: new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (88955) wifi: STA_DISCONNECTED, reason:15
I (91015) wifi: STA_DISCONNECTED, reason:205
I (91135) wifi: new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (91135) wifi: state: init -> auth (b0)
I (91145) wifi: state: auth -> assoc (0)
I (91155) wifi: state: assoc -> run (10)
I (95155) wifi: state: run -> init (2c0)
I (95155) wifi: new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (95155) wifi: new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (95165) wifi: STA_DISCONNECTED, reason:15
I (97225) wifi: STA_DISCONNECTED, reason:205
...
I'm using MicroPython 1.12 with an Adafruit HUZZAH32 board.

User avatar
tve
Posts: 216
Joined: Wed Jan 01, 2020 10:12 pm
Location: Santa Barbara, CA
Contact:

Re: WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

Post by tve » Thu Mar 12, 2020 4:17 am

You are correct. IMHO the code in modnetwork.c should be rearranged a bit so it returns the previous error while connecting, or perhaps at least return it once and then switch to "connecting". As it stands, if you wait for the error to occur (which you don't know when it exactly happens...) and then call disconnect() and follow that with status() then you should see the error code you expect. This is just from reading the source, so there may be a gotcha that I overlooked. In any case, it's an ugly work-around.

User avatar
ghawkins
Posts: 5
Joined: Wed Mar 11, 2020 10:00 pm
Location: Zurich, Switzerland
Contact:

Re: WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

Post by ghawkins » Thu Mar 12, 2020 8:32 pm

Thanks for your reply tve - I tried various iterations of your idea but still didn't get very informative statuses.

I wrote my own status function like so:

Code: Select all

def status(wlan, timeout_ms):
    start = time.ticks_ms()
    while True:
        s = wlan.status()
        if s != network.STAT_CONNECTING:
            return s
        if time.ticks_diff(time.ticks_ms(), start) > timeout_ms:
            wlan.disconnect()
            return wlan.status()
And then used it like so:

Code: Select all

sta.connect("Valid SSID", "invalid password")
print(status(sta, 8000))
I consistently just got back 205, i.e. CONNECTION_FAIL, rather than something indicating a password problem. I don't know if the issue lies with my AP, the ESP-IDF logic or the internal MicroPython logic.

Note: the full set of codes, including CONNECTION_FAIL, can be found in esp-idf/.../esp_wifi_types.h (just search for "WIFI_REASON").

I see that MicroPython 1.12 is using esp_event_loop_init and its associated functions and that these belong to what Espressif now describe as their legacy event loop API.

I also tried a fancier approach, where I started with a very low timeout and gradually increased it:

Code: Select all

def join(*args, **kwargs):
    timeout=kwargs.pop("timeout", 100)
    while True:
        sta.connect(*args, **kwargs)
        print("Waitng {}ms".format(timeout))
        time.sleep_ms(timeout)
        if sta.isconnected():
            return
        sta.disconnect()
        s = sta.status()
        print("Status", s)
        timeout = timeout * 2
        if timeout > MAX_TIMEOUT:
            return
Here the join function also does the connect and you use it like so:

Code: Select all

sta = network.WLAN(network.STA_IF)
sta.active(True)
join("Valid SSID", "invalid password")
However, this produced even odder results. Even when using a correct password, I'd sometimes see quite unexpected intermediate statuses, e.g. AUTH_FAIL, before the timeout got long enough and it had enough time to successfully establish a connection. But with both good and bad passwords I generally saw ASSOC_LEAVE as the intermediate status code and with bad passwords, I never consistently saw statuses that indicated that it was a bad password that was the problem.

Oh dear - it looks like I'll just have to report some nebulous catch-all error message to the end-user ;(

User avatar
jimmo
Posts: 2059
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

Post by jimmo » Mon Mar 16, 2020 4:32 am

ghawkins wrote:
Thu Mar 12, 2020 8:32 pm
I consistently just got back 205, i.e. CONNECTION_FAIL, rather than something indicating a password problem. I don't know if the issue lies with my AP, the ESP-IDF logic or the internal MicroPython logic.
I wonder if the key here is that immediately before the CONNECTION_FAIL, there's a reason=15 (i.e. WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT). (I know very little about WiFi, is it possible that your AP silently drops the auth rather than telling you it's the wrong password? some sort of security measure??).
tve wrote:
Thu Mar 12, 2020 4:17 am
IMHO the code in modnetwork.c should be rearranged a bit so it returns the previous error while connecting
This then masquerades the issue because the two status codes arrive at the same time so you'll only ever see CONNECTION_FAIL.

Maybe modnetwork.c should be updated that if wifi_sta_disconn_reason is already non-zero, to not overwrite it.

karunt
Posts: 3
Joined: Tue Dec 29, 2020 7:24 pm

Re: WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

Post by karunt » Tue Dec 29, 2020 7:28 pm

Has anyone by any chance figured a solution out to this WLAN.status() problem? I'm new to working with micropython and ESP32 boards and am having a hard time figuring out how to force stop a WLAN.connect() process if user enters an incorrect password. I've realized that a successful connection gives results in WLAN.status() value of "1010". I guess one way could be to cause the WLAN.connect() process to timeout after a few seconds if WLAN.status() doesn't equal 1010? Any other thoughts/ideas?

marcidy
Posts: 5
Joined: Sat Dec 12, 2020 11:07 pm

Re: WLAN.status() always reports STAT_CONNECTING but expect STAT_WRONG_PASSWORD

Post by marcidy » Mon Jan 11, 2021 2:29 am

I'm looking at this now on 1.13, and I don't see how to capture the STAT_WRONG_PASSWORD at all.

The reconnect loop, which is a great feature, gives no ability to collect the right status since it leaps right into a new connection.

modnetwork.c, in func event_handler

Code: Select all

            if (wifi_sta_connect_requested) {
                wifi_mode_t mode;
                if (esp_wifi_get_mode(&mode) == ESP_OK) {
                    if (mode & WIFI_MODE_STA) {
                        // STA is active so attempt to reconnect.
                        esp_err_t e = esp_wifi_connect();
                        if (e != ESP_OK) {
                            ESP_LOGI("wifi", "error attempting to reconnect: 0x%04x", e);
                        }
                    }
                }
            }
where wifi_sta_connect_requested is set in func

Code: Select all

esp_connect
.

Auto reconnect is great, absolutely must remain the default case, IMO.

This may be one case where it would be nice to control it with an arg passed to connect.

I don't see how to capture this issue without controlling the auto reconnect without some other structure to store the state while attempting to reconnect.

There might be something else preventing capturing the arg but the current state of wifi will always be connecting while the reconnect loop is running. It prevents feeding back to an end user that the credentials are incorrect in the case where the SSID was correct but the password was not.

Post Reply