micropython / micropython-esp32

Old port of MicroPython to the ESP32 -- new port is at https://github.com/micropython/micropython
MIT License
669 stars 216 forks source link

AP issues with latest branch #221

Open 0xDBFB7 opened 6 years ago

0xDBFB7 commented 6 years ago

I have a simple Wifi AP mode setup page, which is served roughly like so:

import network
import socket

ap = network.WLAN(network.AP_IF)
sta_if = network.WLAN(network.STA_IF)

ap.active(True)
sta_if.active(True)
ap.config(essid="test")
ap.ifconfig(('1.1.1.1', '255.255.255.0', '1.0.0.0', '8.8.8.8'))
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
s.settimeout(200)
while True:
    try:
        cl, addr = s.accept()
        print('client connected from', addr)
    except:  # timeout
        s.close()
        sta_if.active(True)
        ap.active(False)
    cl.close()

On esp32-20170725-v1.9.1, if I try to connect to 1.1.1.1, I get:

I (3885) wifi: mode : softAP (24:0a:c4:83:23:fd)
I (3885) wifi: mode : sta (24:0a:c4:83:23:fc) + softAP (24:0a:c4:83:23:fd)
I (3895) wifi: event 12
I (3895) wifi: STA_START
I (3905) wifi: event 13
I (3905) wifi: event 12
I (16845) wifi: n:1 1, o:1 0, ap:1 1, sta:0 0, prof:1
I (16845) wifi: station: 4c:34:88:a8:02:c3 join, AID=1, n, 40U
I (16855) wifi: event 14
client connected from ('1.1.1.2', 48019)
client connected from ('1.1.1.2', 48021)
client connected from ('1.1.1.2', 48022)
client connected from ('1.1.1.2', 48020)
client connected from ('1.1.1.2', 48025)

On the latest builds, a browser can't connect to 1.1.1.1, and no connection attempt is registered.

I (111806) wifi: mode : null
I (111806) wifi: mode : softAP (24:0a:c4:83:23:fd)
I (111806) wifi: mode : sta (24:0a:c4:83:23:fc) + softAP (24:0a:c4:83:23:fd)
I (111816) network: event 13
I (111816) wifi: STA_START
I (111826) network: event 14
I (111826) network: event 13
I (244206) wifi: n:1 1, o:1 0, ap:1 1, sta:0 0, prof:1
I (244206) wifi: station: 4c:34:88:a8:02:c3 join, AID=1, n, 40U
I (244206) network: event 15
I (306936) wifi: station: 4c:34:88:a8:02:c3 leave, AID = 1
I (306936) wifi: n:1 0, o:1 1, ap:1 1, sta:0 0, prof:1
I (306936) wifi: mode : sta (24:0a:c4:83:23:fc)
I (306936) network: event 16
0xDBFB7 commented 6 years ago

Has the AP API (heh) changed in the last little bit? I've seen some things regarding AP DNS changes, is that perhaps related?

MrSurly commented 6 years ago

Those changes were to correctly get/set the DNS info for the access point. I assume you're using your computer WiFi to connect to the AP? Do you get proper IP / routing info over DHCP? When you connect in the browser, are you using an IP or a name?

MrSurly commented 6 years ago

I've seen some things regarding AP DNS changes, is that perhaps related?

Yes, it's related. I'm investigating (my PR), though it's pretty weird; Might be an IDF bug.

MrSurly commented 6 years ago

Opened issue with IDF: https://github.com/espressif/esp-idf/issues/1257

@BasedOnTechnology You're seeing the problem you are because the AP is giving out IP addresses for the "old" IP range of 192.168.4.0/24, when it should be giving out IPs from 1.1.1.0/24.

Here's a workaround for now: https://github.com/MrSurly/micropython-esp32/tree/mp_issue_221_workaround

MrSurly commented 6 years ago

@dpgeorge @nickzoic

Do we want a crappy work-around for now? I was going to move the tcpip_adapter_get_dns_info call into the "read from" code block, and possibly add a small delay (in case someone calls ifconfig() and ifconfig(settings) back-to-back) for good measure.

0xDBFB7 commented 6 years ago

@MrSurly Sorry, I didn't see this before. Thank you very much for the workaround.

nickzoic commented 6 years ago

Hi all. Is this just a race condition where the station is connecting to the AP before the AP is reconfigured? Can that be resolved by calling ap.ifconfig() before ap.active(True)?

MrSurly commented 6 years ago

Hi all. Is this just a race condition where the station is connecting to the AP before the AP is reconfigured? Can that be resolved by calling ap.ifconfig() before ap.active(True)?

No, I tested this myself, only connecting the station well after the AP was up. By not calling tcpip_adapter_get_dns_info() (note this is a get), the problem goes away. Or, if you add a short delay after calling it. By rights, that call shouldn't affect the DHCP server at all.

MrSurly commented 6 years ago

Okay, so the IDF folks cannot reproduce this; I doubt they're running MP. I'm trying to create a minimal recreation for them, and ... I can't reproduce it, either.

But it's definitely happening in MP.

Can someone look at the code below, and tell me if it's pretty close to matching the code flow in MP?

#include <stdio.h>

#include <esp_task_wdt.h>
#include <esp_wifi.h>
#include <esp_wifi_types.h>
#include <esp_event_loop.h>
#include <nvs_flash.h>

#include <string.h>

#define L(tag, ...) do { printf("[%8s]: ", tag); printf(__VA_ARGS__); printf("\n");} while(false)

static esp_err_t eventHandler(void *ctx, system_event_t *event) {
    const char * TAG = "Event";
    switch (event->event_id) {
        case SYSTEM_EVENT_STA_START:
            L(TAG, "STA_START");
            break;
        case SYSTEM_EVENT_STA_GOT_IP:
            L(TAG, "got ip");
            break;

        case SYSTEM_EVENT_STA_DISCONNECTED: 
            {

                // This is a workaround as ESP32 WiFi libs don't currently
                // auto-reassociate.
                system_event_sta_disconnected_t *disconn = &event->event_info.disconnected;
                L(TAG, "STA_DISCONNECTED, reason:%d", disconn->reason);
                switch (disconn->reason) {
                    case WIFI_REASON_BEACON_TIMEOUT:
                        L(TAG,"beacon timeout");
                        break;
                    case WIFI_REASON_NO_AP_FOUND:
                        L(TAG,"no AP found");
                        break;
                    case WIFI_REASON_AUTH_FAIL:
                        L(TAG,"authentication failed");
                        break;

                    default:
                        // Let other errors through and try to reconnect.
                        break;
                }

            }
            break;

        default:
            L(TAG, "Some unhandled event: %d", event->event_id);
    }
    return ESP_OK;
}

static void wifiTask(void* ctx) {
    const char * TAG = "WifiMon";

    L(TAG, "starting");

    tcpip_adapter_init();
    esp_event_loop_init(eventHandler, NULL);

    const char * ssid = "Mango";

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    if (esp_wifi_init(&cfg) != ESP_OK) printf("init failed\n");
    if (esp_wifi_set_storage(WIFI_STORAGE_RAM) != ESP_OK) printf("init failed\n");
    if (esp_wifi_set_mode(0) != ESP_OK) printf("set mode 0 failed\n");
    if (esp_wifi_start() != ESP_OK) printf("start\n");

    {
        if(esp_wifi_set_mode(WIFI_MODE_AP) != ESP_OK) printf("set mode ap failed\n");
        if(esp_wifi_set_mode(WIFI_MODE_STA | WIFI_MODE_AP) != ESP_OK) printf("set mode ap + sta failed\n");

        static wifi_config_t config;

        if(esp_wifi_get_config(WIFI_IF_AP, &config) != ESP_OK) printf("get config failed\n");
        strcpy((char *)config.ap.ssid, ssid);
        config.ap.ssid_len = strlen(ssid);
        config.ap.password[0] = 0;

        esp_err_t e = esp_wifi_set_config(WIFI_IF_AP, &config);
        if(e != ESP_OK) printf("set config failed: %d\n", e);

#if 1

        tcpip_adapter_ip_info_t info;
        tcpip_adapter_dns_info_t dns_info;

        tcpip_adapter_get_ip_info(WIFI_IF_AP, &info);
        tcpip_adapter_get_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info);

        info.ip.addr                = 0x01010101; // 1.1.1.1
        info.gw.addr                = 0x01000000; // 1.0.0.0
        info.netmask.addr           = 0xFFFFFF00; // 255.255.255.0
        dns_info.ip.u_addr.ip4.addr = 0x08080808; // 8.8.8.8

        tcpip_adapter_dhcps_stop(WIFI_IF_AP);
        tcpip_adapter_set_ip_info(WIFI_IF_AP, &info);
        tcpip_adapter_set_dns_info(WIFI_IF_AP, TCPIP_ADAPTER_DNS_MAIN, &dns_info);
        tcpip_adapter_dhcps_start(WIFI_IF_AP);
#endif

        vTaskDelete(NULL);

    }
}

void app_main() {
    nvs_flash_init(); 
    TaskHandle_t wifiTaskHandle;
    xTaskCreate(wifiTask, "wifiTask", 2048, NULL, tskIDLE_PRIORITY, &wifiTaskHandle);
};