← index #17339Issue #14382
Likely Duplicate · medium · value 0.396
QUERY · ISSUE

sta_if.status() unreliable

openby robtinkersopened 2025-05-22updated 2026-03-16
bugport-esp32

Port, board and/or hardware

esp32 port

MicroPython version

MicroPython v1.25.0 on 2025-04-15; Generic ESP32 module with ESP32

Reproduction

import network, time
from sys import print_exception

REAL_SSID = 'MyNetwork'
REAL_PASS = 'MyPassword'

NETWORKS = (('FakeNetwork1', '12345678'), (REAL_SSID, REAL_PASS), ('FakeNetwork2', '12345678'), ('FakeNetwork3', '12345678'))

STATUS_LOOKUP = {
    network.STAT_ASSOC_FAIL: 'ASSOC_FAIL',
    network.STAT_BEACON_TIMEOUT: 'BEACON_TIMEOUT',
    network.STAT_CONNECTING: 'CONNECTING',
    network.STAT_CONNECT_FAIL: 'CONNECT_FAIL',
    network.STAT_GOT_IP: 'GOT_IP',
    network.STAT_HANDSHAKE_TIMEOUT: 'HANDSHAKE_TIMEOUT',
    network.STAT_IDLE: 'IDLE',
    network.STAT_NO_AP_FOUND: 'NO_AP_FOUND',
    network.STAT_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD: 'NO_AP_FOUND_IN_AUTHMODE_THRESHOLD',
    network.STAT_NO_AP_FOUND_IN_RSSI_THRESHOLD: 'NO_AP_FOUND_IN_RSSI_THRESHOLD',
    network.STAT_NO_AP_FOUND_W_COMPATIBLE_SECURITY: 'NO_AP_FOUND_W_COMPATIBLE_SECURITY',
    network.STAT_WRONG_PASSWORD: 'WRONG_PASSWORD',
}

def print_status_loop(interface, duration):
    old_status = None
    t0 = time.ticks_ms()
    while True:
        tt = time.ticks_diff(time.ticks_ms(), t0)
        if tt > duration * 1000:
            break
        status = interface.status()
        if old_status != status:
            old_status = status
            print(tt, STATUS_LOOKUP.get(status, str(status)))

sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)

for network in NETWORKS:
    print( '======== disconnect()')
    try: sta_if.disconnect()
    except Exception as e: print_exception(e)
    print_status_loop(sta_if, 5)
    print(f'======== connect({network[0]}, ...)')
    sta_if.connect(*network)
    print_status_loop(sta_if, 5)

Expected behaviour

I would expect the connect() call to reliably initialise the status to something (CONNECTING?)

I would expect the disconnect() call to reliably set the status to something (IDLE?)

Observed behaviour

connect() only works as I expect if the previous connect() call eventually GOT_IP, but not otherwise.

disconnect() almost works as I expect if the previous connect() call eventually GOT_IP, but not otherwise.

======== disconnect()
0 IDLE
======== connect(FakeNetwork1, ...)
0 CONNECTING
2417 NO_AP_FOUND
======== disconnect()
0 NO_AP_FOUND
======== connect(MyNetwork, ...)
0 NO_AP_FOUND
1398 GOT_IP
======== disconnect()
0 GOT_IP
1 IDLE
======== connect(FakeNetwork2, ...)
0 IDLE
2417 NO_AP_FOUND
======== disconnect()
0 NO_AP_FOUND
======== connect(FakeNetwork3, ...)
0 NO_AP_FOUND

Additional Information

I would like to loop through a bunch of pre-configured wifi networks to find one that works (e.g. for a portable device).

Unfortunately if a .connect() call doesn't eventually connect (the usual case in my scenario), then polling .status() becomes unreliable and I have to guess an appropriate timer and wait for .isconnected() for each ssid/pass, significantly slowing down startup if the working network is down the list.

Code of Conduct

Yes, I agree

CANDIDATE · ISSUE

ESP32-C3-MINI-1(DK):network.WLAN can not connect success anymore if 201 status appears

openby shiwaimanongopened 2024-04-26updated 2025-03-03
bugport-esp32needs-info

Checks

  • I agree to follow the MicroPython Code of Conduct to ensure a safe and respectful space for everyone.

  • I've searched for existing issues matching this bug, and didn't find any.

Port, board and/or hardware

ESP32-C3-MINI-1(DK) ESP-ROM:esp32c3-api1-20210207

MicroPython version

MicroPython v1.22.2 on 2024-02-22; ESP32C3 module with ESP32C3

Reproduction

run code:

'''
如果先激活WLAN再激活AP, 则会出错 OSError: Wifi Invalid Mode
'''
import network, time, json, machine
import uasyncio as asyncio

# 先开AP
ap = network.WLAN(network.AP_IF)
ap.config(essid='ESP32-C3', password='12345678')
ap.config(max_clients=3)
ap.active(False)
ap.active(True)
print('AP信息:', ap.ifconfig())


wlan = network.WLAN(network.STA_IF)
wlan.active(False)
wlan.active(True)

connect_wifi_task = ''

async def run_connect_wifi_task(ssid, password):
    while True:
        try:
            wlan.active(False)
            wlan.active(True)
            wlan.connect(ssid, password)
            print('开始连接', ssid, password)

            count = 0
            while not wlan.isconnected():
                count += 1
                print('连接重试:', count, wlan.status())

                if count == 10:
                    raise Exception('超时')

                if wlan.status() == 201:
                    raise Exception('没有找到网络')

                await asyncio.sleep(1)
            pass
        except Exception as e:
            print('连接出错', e)
            # 立即关闭WLAN, 防止造成AP异常
            wlan.active(False)
            await asyncio.sleep(6)
    pass

    print('WLAN信息:', wlan.ifconfig())

def connect_wifi(ssid, password):
    print('连接', ssid, password)

    global connect_wifi_task
    if connect_wifi_task != '':
        connect_wifi_task.cancel()
        connect_wifi_task = ''
    pass

    connect_wifi_task = asyncio.create_task(run_connect_wifi_task(ssid, password))
pass

# 处理HTTP请求
async def http_handle(reader, writer):
    client = writer.get_extra_info('peername')
    print(f'HTTP客户端连接 {client}')

    # 读取方法路径协议行
    line_path = await reader.readline()
    line_path_text = str(line_path)
    print(f'HTTP方法路径协议行 {line_path_text}')

    # 读取Headers
    # https://github.com/micropython/micropython/blob/d11ca092f75d2652df403dda7448fe1bc8f98cf7/tests/net_inet/asyncio_tcp_read_headers.py#L10
    print('Headers 如下:')
    while True:
        line = await reader.readline()
        line = line.strip()
        if not line:
            break
        print(str(line, 'utf-8'))
    pass
    print('Headers ----')

    if line_path_text.find("b'GET /") != -1:
        print('HTTP客户端GET请求')
        writer.write('HTTP/1.1 200 OK\r\nContent-type: text/html; charset=utf-8\r\n\r\n')
        writer.write(f"""<!DOCTYPE html>
<html>
    <head> <title>里路微控</title> </head>
    <body>
        <h1>里路微控</h1>
        <p>{time.localtime()}</p>
        <p>来自 <a href="https://lilu.red">里路</a></p>
    </body>
</html>
""")
        pass

    if line_path_text.find("b'POST /") != -1:
        print('HTTP客户端POST请求')

        # 读取Body
        body_data = await reader.read(512)
        body_text = str(body_data, 'utf-8')
        print('Body 如下:')
        print(body_text)
        print('Body ----')

        # 解析数据
        post_data = json.loads(body_text)

        # 按逻辑处理
        if line_path_text.find("b'POST /wifi ") != -1: # 设置WIFI
            print(f'HTTP客户端POST请求设置WIFI')
            if 'wifi_ssid' not in post_data or post_data['wifi_ssid'] == '' or 'wifi_password' not in post_data or post_data['wifi_password'] == '':
                print('HTTP设置WIFI数据无效')
                writer.write('HTTP/1.1 400 Bad Request\r\n\r\n')
                pass
            else:
                connect_wifi(post_data['wifi_ssid'], post_data['wifi_password'])
                writer.write('HTTP/1.1 200 OK\r\n\r\n')
                pass
        else:
            print(f'HTTP客户端POST请求不在预期范围 {line_path_text}')
            writer.write('HTTP/1.1 400 Bad Request\r\n\r\n')
        pass
    pass

    # 发送响应内容
    await writer.drain()

    # 关闭
    writer.close()
    await writer.wait_closed()
    print('HTTP客户端断开')
pass

async def main():
    asyncio.create_task(asyncio.start_server(http_handle, "0.0.0.0", 80))

    # asyncio.create_task(connect_wifi('a', '12345678'))

    while True:
        await asyncio.sleep(1)
pass

try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("主动关闭")
finally:
    asyncio.new_event_loop()

Post not exists SSID {"wifi_password": "wrong12345678", "wifi_ssid": "kmx"} to http://192.168.4.1/wifi :

连接 kmx wrong12345678
开始连接 kmx wrong12345678
连接重试: 1 1001
HTTP客户端断开
连接重试: 2 1001
连接重试: 3 1001
连接重试: 4 201
连接出错 没有找到网络

if wlan.status() == 201 , Post right SSID {"wifi_password": "wrong12345678", "wifi_ssid": "km"} to http://192.168.4.1/wifi :

连接 km wrong12345678
开始连接 km wrong12345678
连接重试: 1 201
连接出错 没有找到网络
HTTP客户端断开
开始连接 km wrong12345678
连接重试: 1 201
连接出错 没有找到网络

wlan.status() always 201...

Expected behaviour

  1. The 201 status should not remain when reconnecting to an right network again.
  2. Regardless of whether it was 201 or 202 status before, network should be reset when reconnecting.
  3. WLAN connection failure should not cause the AP to disconnect.

Observed behaviour

When reconnect to right SSID with wrong password, the wlan.status() should be 202. After testing, it was found that the board may still be connected to the previous SSID(kmx).

When wlan.status() is 201 , I must call wlan.active(False) immediately. If not do this, the AP will shutdown automatic. But after call wlan.active(False) , the AP can continue to work.

And if connect to right SSID with wrong password at first time(wlan.status() is 202), Then post right SSID and right password, The board can connect successful.

Additional Information

The user's situation is much more complicated when distributing the network. Hope the API behaves as expected. Thanks very much.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied