Skip to content

Feature request: wifimulti persistent support #2698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
tablatronix opened this issue Nov 19, 2016 · 19 comments
Closed

Feature request: wifimulti persistent support #2698

tablatronix opened this issue Nov 19, 2016 · 19 comments

Comments

@tablatronix
Copy link
Contributor

Add sdk persistent support for wifimulti.

Some info from @kentaylor

kentaylor commented on May 10

I looked into this a bit more. It turns out the device will store data for up to 5 WiFi access points. It will only use one of them rather than switch between them by itself but once one is selected it will handle the connectivity automatically. The Espressif SDK functions you would use are:-

  1. wifi_station_ap_number_set to set how many to save, might as well make it 5.
  2. wifi_station_get_ap_info which returns details of the access points recorded and can be tested against the list of scanned access points.
  3. wifi_station_ap_change to set which one to use.
    See function definitions in sedctions 3.4.10 - 3.4.12 at http://www.mikrocontroller.net/attachment/245197/2C-SDK-Espressif_IoT_SDK_Programming_Guide_v0.9.5.pdf .

The algorithm when you save one would be choose the next empty one to save to. If there is already 5 saved, delete number 1. Then move 2 to 1 etc to make a vacancy at 5 and store the new one at 5.
At startup, scan for WiFi networks then change to the one from the scan list with the strongest signal that matches the SSID of one of the stored ones.

ref: tzapu/WiFiManager#166

@tablatronix tablatronix changed the title Feature: wifimulti persisent support Feature: wifimulti persistent support Nov 19, 2016
@tablatronix
Copy link
Contributor Author

Has this been considered or dealt with elsewhere?

@devyte devyte added this to the 2.6.0 milestone Jan 8, 2018
@a-c-sreedhar-reddy
Copy link
Contributor

Who is working on this enhancement?

@devyte
Copy link
Collaborator

devyte commented Feb 22, 2019

Nobody atm, current focus is on stabilizing 2.5.0.

@tavdog
Copy link

tavdog commented Jun 22, 2019

I would love this feature !

@d-a-v d-a-v changed the title Feature: wifimulti persistent support Feature request: wifimulti persistent support Aug 28, 2019
@d-a-v
Copy link
Collaborator

d-a-v commented Aug 28, 2019

Is anybody willing to work on this ?

@d-a-v d-a-v modified the milestones: 2.6.0, 3.0.0 Aug 28, 2019
@a-c-sreedhar-reddy
Copy link
Contributor

should the available wifi's be stored in FLASH?

@devyte
Copy link
Collaborator

devyte commented Aug 29, 2019

@tablatronix? I thought this was just for forwarding the persistent flag from multi to wifi, but reading your original description says otherwise.

@tablatronix
Copy link
Contributor Author

Yes it is to make the wifimulti persistent, I have not tested the SDK functions above to test if this even works though.

@Erriez
Copy link
Contributor

Erriez commented Oct 3, 2020

FYI: Yesterday my WiFi Multi redesign is merged into master.

@devyte requested to look at this old request from @tablatronix and I made a proof of concept. Please find my results below:

The ESP8266 contains an array to store up to 5 WiFi configurations to flash. You're right: wifi_station_ap_number_set() must be called in order to change the default from 1 to 5.

After this change, new configurations can be saved to flash with wifi_station_set_config(). It looks like saving the configs in a ring, but I could not reliable save multiple SSID's after each other without a system_restart(). (It is vague in the datasheet how it works)

The ESP82866 does not automatically connect to the next registered network on connection failure. It must be called manually with wifi_station_ap_change(index);.

However: Saving WiFi credentials to flash contains a serious security issue.

Consider the following use case:

  • Store one or more SSID/Passwords in flash with wifi_station_set_config().
  • Keep the ESP8266 operating in your garden or somewhere else.
  • A hacker steals your ESP8266 device.
  • The hacker writes the following exploit to the ESP8266 and overwrites the sketch:
// Fixed 5 configs
#define NUM_CONFIGS 5

void printConfigs()
{
    struct station_config config[NUM_CONFIGS];
    
    // Clear config
    memset(config, 0, sizeof(config));

    // Print configs
    Serial.printf(PSTR("Get AP info: %s\n"), wifi_station_get_ap_info(config) ? "Ok" : "Failed");
    for (uint8_t i = 0; i < NUM_CONFIGS; i++) {
        Serial.printf(PSTR("Config %d:\n"), i);
        Serial.printf(PSTR("  ssid:      %s\n"), config[i].ssid);
        Serial.printf(PSTR("  password:  %s\n"), config[i].password);
        Serial.printf(PSTR("  bssid_set: %d\n"), config[i].bssid_set);
        Serial.printf(PSTR("  bssid:     %02x:%02x:%02x:%02x:%02x\n"), 
            config[i].bssid[0], config[i].bssid[1], config[i].bssid[2],
            config[i].bssid[3], config[i].bssid[4], config[i].bssid[5]);
        Serial.printf(PSTR("  threshold.rssi: %d\n"), config[i].threshold.rssi);
        Serial.printf(PSTR("  threshold.authmode: %d\n"), (uint8_t)config[i].threshold.authmode);
    }
}

Now all SSID's, passwords and MAC addresses are printed on the serial console in plain text which allows the hacker to come back and login to your WiFi networks... I know, security is a different topic, but I'm a little bit disappointed about this weak ESP8266 implementation.

I also noticed that this applicable in the current master version. For this reason, I think saving the WiFi credentials in plain text to flash is not the way forward... It would be more save to store SSID/password in encrypted flash with WiFi.persistent(false); to disable saving passwords this way.

What is your opinion?

Official API documentation:
https://www.espressif.com/sites/default/files/documentation/2c-esp8266_non_os_sdk_api_reference_en.pdf

Test sketch to experiment:

#include <ESP8266WiFi.h>
#include <PolledTimeout.h>

#define NUM_CONFIGS   5

#define WIFI1_SSID  ""
#define WIFI1_PASS  ""
const uint8_t WIFI1_BSSID[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

#define WIFI2_SSID  ""
#define WIFI2_PASS  ""
const uint8_t WIFI2_BSSID[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

#define WIFI3_SSID  ""
#define WIFI3_PASS  ""
const uint8_t WIFI3_BSSID[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

#define WIFI4_SSID  ""
#define WIFI4_PASS  ""
const uint8_t WIFI4_BSSID[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

uint8_t configIndex;


void eraseConfig()
{
    struct station_config config;

    memset(&config, 0, sizeof(station_config));

    // Get current config from flash
    wifi_station_get_config_default(&config);
    
    if (strlen((const char *)config.ssid) > 0) {
        Serial.println(F("System restore..."));
        system_restore();
        Serial.println(F("System restart..."));
        system_restart();
        delay(1000);
        Serial.println(F("Never reached!"));
    }
}

void setAutoConnect(bool set)
{    
    if (wifi_station_get_auto_connect() != set) {
        Serial.printf(PSTR("Set auto connect %d: %s"), 
            set, wifi_station_set_auto_connect(set) ? "OK" : "Failed");
    }

    Serial.printf(PSTR("Auto connect: %d\n"), wifi_station_get_auto_connect());
}

void saveConfig(const char *ssid, const char *password, const uint8_t *bssid=NULL)
{
    struct station_config stationConf;

    // The number of APs that can be recorded (MAX: 5)
    if (wifi_station_ap_number_set(5)) {
        Serial.println(F("wifi_station_ap_number_set(): OK"));
    } else {
        Serial.println(F("wifi_station_ap_number_set(): Failed"));
    }

    Serial.printf(PSTR("Saving: %s, %s\n"), ssid, password);

    memset(&stationConf, 0, sizeof(stationConf));
    
    os_memcpy(&stationConf.ssid, ssid, 32);
    os_memcpy(&stationConf.password, password, 64);
    if (bssid != NULL) {
        os_memcpy(&stationConf.bssid, WIFI1_BSSID, 6);
        stationConf.bssid_set = 1; // 1: Check MAC address AP
    } else {
        stationConf.bssid_set = 0; // 0: No check MAC address AP
    }
    
    wifi_station_set_config(&stationConf);

    // Needed as it is not saved? Hmm, delay does not make sense...
    delay(1000);
}

void printConfigs()
{
    struct station_config config[NUM_CONFIGS];
    
    // Clear config
    memset(config, 0, sizeof(config));

    // Print fixed 5 configs
    Serial.printf(PSTR("Get AP info: %s\n"), wifi_station_get_ap_info(config) ? "Ok" : "Failed");
    for (uint8_t i = 0; i < NUM_CONFIGS; i++) {
        Serial.printf(PSTR("Config %d:\n"), i);
        Serial.printf(PSTR("  ssid:      %s\n"), config[i].ssid);
        Serial.printf(PSTR("  password:  %s\n"), config[i].password);
        Serial.printf(PSTR("  bssid_set: %d\n"), config[i].bssid_set);
        Serial.printf(PSTR("  bssid:     %02x:%02x:%02x:%02x:%02x\n"), 
            config[i].bssid[0], config[i].bssid[1], config[i].bssid[2],
            config[i].bssid[3], config[i].bssid[4], config[i].bssid[5]);
        Serial.printf(PSTR("  threshold.rssi: %d\n"), config[i].threshold.rssi);
        Serial.printf(PSTR("  threshold.authmode: %d\n"), (uint8_t)config[i].threshold.authmode);
    }
    
    // Get current API ID
    configIndex = wifi_station_get_current_ap_id();
    Serial.printf(PSTR("Current AP ID: %d\n"), configIndex);
}

void connectNextAP()
{
    configIndex++;
    configIndex %= NUM_CONFIGS;

    Serial.printf(PSTR("\nConnecting to: %d\n"), configIndex);

    wifi_station_ap_change(configIndex);

    using esp8266::polledTimeout::oneShotMs;
    oneShotMs connectTimeout(6000);
    do {
        delay(10);
    } while (!connectTimeout && (WiFi.status() != WL_CONNECTED));

    delay(1000);
}

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

    // Erase config from flash
    //eraseConfig();

    // Set in station mode before config
    WiFi.mode(WIFI_STA);

    // Set auto connect
    setAutoConnect(true);

    // Save config
#if 0
    saveConfig(WIFI1_SSID, WIFI1_PASS, NULL);
    saveConfig(WIFI2_SSID, WIFI2_PASS, NULL);
    saveConfig(WIFI3_SSID, WIFI3_PASS, NULL);
#endif

    // Connect to config index 0..4
#if 0
    // Force changing to other AP as this is not done automatically
    if (wifi_station_ap_change(0)) {
        Serial.println(F("wifi_station_ap_change(): OK"));
    } else {
        Serial.println(F("wifi_station_ap_change(): Failed"));
    }
#endif

    printConfigs();
}

void loop() 
{
    if (wifi_station_get_connect_status() == 5) {
        Serial.printf(PSTR("Connected %s\n"), WiFi.SSID());
    } else {
        Serial.println(F("Disconnected"));
    }

    delay(1000);

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

@tablatronix
Copy link
Contributor Author

tablatronix commented Oct 3, 2020

However: Saving WiFi credentials to flash contains a serious security issue.

This is unrelated, and it entirely doable right now simply by just dumping flash, but a good point to bring up in an esp sdk issue, there is no reason it cannot be hashed, but its hard to hide them if the user has the device..

@Erriez
Copy link
Contributor

Erriez commented Oct 7, 2020

@tablatronix and @devyte, I dived deep into the SDK:

It turns out the device will store data for up to 5 WiFi access points.

This is correct.

It will only use one of them

Correct: The ESP8266 can use one of the registered WiFi AP configurations.

rather than switch between them by itself

  • It turns out that the ESP8266 has no hardware built-in algorithm to automatically switch to an AP with strongest RSSI. This must be done by library/application code.

once one is selected it will handle the connectivity automatically.

Partially correct:

  • When the WiFi connection is lost, it always tries to reconnect to the same network, even when the AP is down.
  • An automatic connect after power-on/reset or connection lost depends on the setting wifi_station_set_auto_connect().
  • Code is needed to: 1. detect a WiFi connection lost. 2. start a new WiFi scan 3. connect to the WiFi with best RSSI with WIFi config stored in RAM or flash.
  • The last connection will be used after power-on or reset when this is saved in flash and auto connect = 1.

Note: AP configurations can be erased with system_restore() which is similar to a factory reset:

  • wifi_station_set_auto_connect = 1
  • wifi_set_phy_mode = PHY_MODE_11N
  • wifi_softap_set_config -> All cleared with value 0
  • wifi_station_set_config -> All cleared with value 0
  • wifi_set_opmode -> SOFTAP_MODE = 2

The algorithm when you save one would be choose the next empty one to save to.

The SDK does not provide an interface to directly address the index of an AP config. It writes a new config incrementally to a new index: 0, 1, 2, 3, 4, wrapping to 0, etc.

Limitation: There is no SDK API to retrieve the number of AP's, set by wifi_station_ap_number_set().
I cannot verify if calling wifi_station_ap_number_set() writes to flash every time to prevent flash wear-out.

Saving multi WiFi configs (max 5) to RAM works as expected (wifi_station_set_config_current()) and can be read all 5 configs with one call (wifi_station_get_ap_info()) before connecting to an AP.

Problem: I encountered a problem to read the saved WiFi configs (max 5) from flash after calling wifi_station_set_config().

  • wifi_station_get_ap_info() returns all 5 WiFi configs stored in RAM and not from flash.
  • wifi_station_get_config_default() returns only the current WiFi config from flash and cannot be selected by an AP index 0..4.

The consequence is that the config index of the SSID/password is unknown after a wifi_station_set_config() call which is needed for the WiFi connect wifi_station_ap_change(ap_index).

A workaround is to reset the CPU with system_reset() after the last wifi_station_set_config() call to read the updated configs from flash, but resetting is not a nice solution.

Test case for persistent to save to flash:

  1. Erase flash once system_restore(); system_restart();
  2. PHY wakeup: wifi_fpm_do_wakeup(); wifi_fpm_close();
  3. Set station mode: wifi_set_opmode(1);
  4. Register 1..5 AP's: wifi_station_set_config(&config);
  5. Read all 5 AP configs: wifi_station_get_ap_info();
    Only the last wifi_station_set_config() is displayed at index 0 which is incorrect. (Bug in SDK?)
    wifi_station_get_config() cannot select index.
  6. Reset CPU and point 5 displays correct configs from flash.
  7. Run WiFi scan
  8. WiFi connect with ap_index 0..4 wifi_station_ap_change(ap_index);

Due too this limitation, I'm not sure how to proceed.

My test code (5 AP's persistent to save to flash):

#include <IPAddress.h>
#include <PolledTimeout.h>
extern "C" {
#include "user_interface.h"
}

// Configure 5 WiFi AP's
#define WIFI_SSID1      ""
#define WIFI_PASS1      ""
#define WIFI_SSID2      ""
#define WIFI_PASS2      ""
#define WIFI_SSID3      ""
#define WIFI_PASS3      ""
#define WIFI_SSID4      ""
#define WIFI_PASS4      ""
#define WIFI_SSID5      ""
#define WIFI_PASS5      ""

#define NUM_APS         5 // MAX 5

#if NUM_APS > 5
#error "Max AP's is fixed to 5 in the SDK"
#endif

// MAKE SURE TO POWER-CYCLE AFTER FLASHING THIS SKETCH

// false: Save AP configs to RAM works!
// true: Save AP configs to flash does NOT work
#define WIFI_PERSISTENT true

typedef enum WiFiMode 
{
    WIFI_STA = 1, 
    WIFI_AP = 2, 
    WIFI_AP_STA = 3
} WiFiMode_t;

void restore()
{
    struct station_config config;

    // Factory reset:
    // - wifi_station_set_auto_connect
    // - wifi_set_phy_mode
    // - wifi_softap_set_config related
    // - wifi_station_set_configrelated
    // - wifi_set_opmode

    // Clear station config
    memset(&config, 0, sizeof(station_config));

    if (!wifi_station_get_config(& config)) {
        Serial.println(F("Failed to retrieve station config"));
        return;
    }

    if (strlen((const char *)config.ssid)) {
        // Get current config from flash
        if (wifi_station_get_config_default(&config)) {
            Serial.println(F("Erasing WiFi credentials..."));
    
            Serial.println(F("System restore..."));
            system_restore();
            Serial.println(F("System restart..."));
            system_restart();
            // The ESP8266 will not restart immediately.
            // Do not call other functions after calling this API.
            while (1) {
                ;
            }
        } else {
            Serial.println(F("Load WiFi config failed"));
        }
    } else {
        Serial.println(F("No WiFi configs found"));
    }
}

void setAPNumber(uint8_t ap_number)
{
    if (!wifi_station_ap_number_set(ap_number)) {
        Serial.println(F("AP set failed"));
    } else {
        Serial.printf(PSTR("AP number set: %d\n"), ap_number);
    }
}

void setMode(uint8_t mode)
{
    if (wifi_fpm_get_sleep_type() == MODEM_SLEEP_T) {
        Serial.println(F("Wakeup"));
        wifi_fpm_do_wakeup();
        wifi_fpm_close();
    }

    if (mode <= 3) {
        if (WIFI_PERSISTENT) {
            if (!wifi_set_opmode(mode)) {
                Serial.println(F("Mode set flash failed"));
                return;
            }
        } else {
            if (!wifi_set_opmode_current(mode)) {
                Serial.println(F("Mode set failed"));
                return;
            }
        }
    } else {
        Serial.println(PSTR("Mode must be 1..3")); // Mode 0?
        return;
    }
    Serial.printf(PSTR("Mode set: %d\n"), wifi_get_opmode());
}

void setCfg(const char *ssid, const char *password, uint8_t rssi=0)
{
    struct station_config stationConf;

    Serial.printf(PSTR("WiFi add config %s\n"), ssid);

    memset(&stationConf, 0, sizeof(stationConf));

    os_memcpy(&stationConf.ssid, ssid, 32);
    os_memcpy(&stationConf.password, password, 64);
    stationConf.threshold.rssi = rssi;

    if (WIFI_PERSISTENT) {
        // Set Wi-Fi Station configuration; save to flash.
        if (!wifi_station_set_config(&stationConf)) {
            Serial.println(F("Set config failed"));
            return;
        }
    } else {
        // Set Wi-Fi Station configuration; setting in flash is not updated.
        if (!wifi_station_set_config_current(&stationConf)) {
            Serial.println(F("Set config failed"));
            return;
        }
    }
}

IPAddress localIP() 
{
    struct ip_info ip;
    
    wifi_get_ip_info(STATION_IF, &ip);

    return IPAddress(ip.ip.addr);
}

const char *SSID()
{
    struct station_config conf;
    
    // SSID can be up to 32chars, => plus null term
    static char tmp[33];
    
    if (wifi_station_get_config(&conf)) {
        memcpy(tmp, conf.ssid, sizeof(conf.ssid));

        // Nullterm in case of 32 char ssid
        tmp[32] = '\0';
    } else {
        Serial.println(F("SSID get config failed"));
        tmp[0] = '\0';
    }
    
    return tmp;
}

uint8_t *BSSID()
{
    static struct station_config conf;
    
    wifi_station_get_config(&conf);
    
    return reinterpret_cast<uint8_t*>(conf.bssid);
}

int8_t RSSI()
{
    return wifi_station_get_rssi();
}

uint8_t channel() 
{
    return wifi_get_channel();
}

void wifiPrintStatus()
{
    IPAddress ip;
    uint8_t *mac;
    station_status_t status;
    
    status = wifi_station_get_connect_status();

    switch (status) {
        case STATION_IDLE:
            Serial.println(F("WiFi idle."));
            break;
        case STATION_CONNECTING:
            Serial.println(F("WiFi connecting."));
            break;
        case STATION_WRONG_PASSWORD:
            Serial.println(F("WiFi wrong password."));
            break;
        case STATION_NO_AP_FOUND:
            Serial.println(F("WiFi no AP found."));
            break;
        case STATION_CONNECT_FAIL:
            Serial.println(F("WiFi station connect fail."));
            break;
        case STATION_GOT_IP:
            ip = localIP();
            mac = BSSID();

            Serial.println(F("Connected:"));
            Serial.printf(PSTR("  SSID: %s\n"), SSID());
            Serial.printf(PSTR("  IP:   %d.%d.%d.%d\n"), ip[0], ip[1], ip[2], ip[3]);
            Serial.printf(PSTR("  MAC:  %02X:%02X:%02X:%02X:%02X:%02X\n"),
                          mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
            Serial.printf(PSTR("  CH:   %d\n"), channel());
            Serial.printf(PSTR("  RSSI: %d\n"), RSSI());
            break;
    }
}

void wifiWaitConnected()
{
    using esp8266::polledTimeout::oneShotMs;
    oneShotMs connectTimeout(10000);
    do {
        delay(10);
        if (wifi_station_get_connect_status() == STATION_GOT_IP) {
            wifiPrintStatus();
            return;
        }
    } while (!connectTimeout);

    Serial.println(F("Timeout"));
}

void wifiConnect()
{
    Serial.println(F("WiFi connect..."));

    // Connect Wi-Fi Station to AP.
    if (!wifi_station_connect()) {
        Serial.println(F("Station connect failed"));
        return;
    }

    wifiWaitConnected();
}

void cmdWiFiAPChangeIndex(uint8_t ap_index)
{
    if (ap_index < 5) {
        Serial.println(F("Disconnecting"));
        if (!wifi_station_disconnect()) {
            Serial.println(F("Disconnect failed"));
        }
        delay(200);

        if (!wifi_station_ap_change(ap_index)) {
            Serial.println(F("AP change failed"));
        } else {
            Serial.printf(PSTR("Connecting AP index %d...\n"), ap_index);

            wifiWaitConnected();

            wifiAPPrint();
        }
    } else {
        Serial.println(PSTR("AP index must be 1..5"));
    }
}

void wifiAPPrint()
{
    // Fixed number of WiFi configurations
    const uint8_t numConfigs = 5;
    struct station_config config[numConfigs];

    // Clear config
    memset(config, 0, sizeof(config));

    // Print configs
    if (wifi_station_get_ap_info(config)) {
        for (uint8_t i = 0; i < numConfigs; i++) {
            Serial.printf(PSTR("Config %d:\n"), i);
            Serial.printf(PSTR("  ssid:      %s\n"), config[i].ssid);
            Serial.printf(PSTR("  password:  %s\n"), config[i].password);
            Serial.printf(PSTR("  bssid_set: %d\n"), config[i].bssid_set);
            Serial.printf(PSTR("  bssid:     %02x:%02x:%02x:%02x:%02x\n"),
                          config[i].bssid[0], config[i].bssid[1], config[i].bssid[2],
                          config[i].bssid[3], config[i].bssid[4], config[i].bssid[5]);
            Serial.printf(PSTR("  threshold.rssi: %d\n"), config[i].threshold.rssi);
            Serial.printf(PSTR("  threshold.authmode: %d\n"), (uint8_t)config[i].threshold.authmode);
        }
        Serial.printf(PSTR("AP index: %d\n"), wifi_station_get_current_ap_id());
    } else {
        Serial.println(F("Load AP info failed"));
    }

    // Print WiFi status
    wifiPrintStatus();

}

void setup()
{
    delay(500);
    Serial.begin(115200);
    Serial.println(F("\nESP8266 Auto Connect proof of concept"));

    // Erase AP config (reset CPU once)
    // Erase all SSID's/passwords, Mode=2, Auto connect = 1
    restore();

    // Set station mode
    setMode(1);
    //delay(1000); // Delay is not needed
    
    // Set AP number
    setAPNumber(NUM_APS);
    //delay(250); // Delay is not needed

    // Add WiFi AP logins (max 5)
    setCfg(WIFI_SSID1, WIFI_PASS1, 0);
    //delay(250); // Delay is not needed
    setCfg(WIFI_SSID2, WIFI_PASS2, 0);
    //delay(250); // Delay is not needed
    setCfg(WIFI_SSID3, WIFI_PASS3, 0);
    //delay(250); // Delay is not needed
    setCfg(WIFI_SSID4, WIFI_PASS4, 0);
    //delay(250); // Delay is not needed
    setCfg(WIFI_SSID5, WIFI_PASS5, 0);
    //delay(250); // Delay is not needed

    //delay(1000); // Delay is not needed

    // Print config
    wifiAPPrint();

    // Hmmm, AP configs not read from flash!
    // Only the last saved config is read at index 0.
    // All AP configs are correct after a CPU reset.
    while (1) {
        delay(100);
    }

    // WiFi connect
    wifiConnect();

    // Print config
    wifiAPPrint();
}

void loop() 
{
    for (uint8_t i = 0; i < NUM_APS; i++) {
        delay(30000);
        cmdWiFiAPChangeIndex(i);
    }
}

Output shows only the last AP config on index 0 which is wrong:

ESP8266 Auto Connect proof of concept
No WiFi configs found
Wakeup
bcn 0
del if1
usl
mode : sta(f4:cf:a2:xx:xx:xx)
add if0
Mode set: 1
AP number set: 5
WiFi add config ssid1
WiFi add config ssid2
WiFi add config ssid3
WiFi add config ssid4
WiFi add config ssid5
Config 0:
  ssid:      ssid5
  password:  *************
  bssid_set: 0
  bssid:     ff:ff:ff:ff:ff
  threshold.rssi: 0
  threshold.authmode: 0
Config 1:
  ssid:      
  password:  
  bssid_set: 0
  bssid:     00:00:00:00:00
  threshold.rssi: 0
  threshold.authmode: 0
Config 2:
  ssid:      
  password:  
  bssid_set: 0
  bssid:     00:00:00:00:00
  threshold.rssi: 0
  threshold.authmode: 0
Config 3:
  ssid:      
  password:  
  bssid_set: 0
  bssid:     00:00:00:00:00
  threshold.rssi: 0
  threshold.authmode: 0
Config 4:
  ssid:      
  password:  
  bssid_set: 0
  bssid:     00:00:00:00:00
  threshold.rssi: 0
  threshold.authmode: 0
AP index: 0
WiFi idle.

@tablatronix
Copy link
Contributor Author

Wow you've done a great job with this, very thorough

@Erriez
Copy link
Contributor

Erriez commented Oct 7, 2020

Thanks! Now finding a solution. :-)

@Abedi98
Copy link

Abedi98 commented Feb 9, 2021

Thanks! Now finding a solution. :-)

Hi . excellent
Please explain how to use your code?
How to save access point information?
Please! Write a real example to use the code you generated

Thanks

@Abedi98
Copy link

Abedi98 commented Feb 9, 2021

Thanks! Now finding a solution. :-)


void rootPage() {
    String content = R"(
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    <b> Tik-Box Configuration </b>
    <form method="POST" action="/postForm">
      <input type="text" name="ssid" value="Write your ssid...">
      <input type="text" name="password" value="Write your wifi password...">
      <input type="submit" value="Save">
    </form>    
    </body>
    </html>
    )";

    server.send(200, "text/html", content);
}


void handlePostForm()
{
      String qsid = server.arg("ssid");
      String qpass = server.arg("password");
      String content;
      int statusCode;
  if(qsid != "" && qpass != ""){
      setCfg("newssid", "1234567890", 0);
      server.send(200, "text/html", "saced");
  }else{
    server.send(200, "text/html", "please fill all input");
  }
}

To save the access point, I wrote the following code. But when a new access point is saved, the previous access point is lost

@Erriez
Copy link
Contributor

Erriez commented Feb 9, 2021

@Abedi98 The easiest way is to use the WiFiMulti example in master:
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino

@Abedi98
Copy link

Abedi98 commented Feb 9, 2021

@Abedi98 The easiest way is to use the WiFiMulti example in master:
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino

I do not want to do this as hard code in setup.
I want to save the ssids and be able to manage them on a separate page

like this :

void rootPage() {
    String content = R"(
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    <b> Configuration </b>
    <form method="POST" action="/postForm">
      <input type="text" name="ssid" value="Write your ssid...">
      <input type="text" name="password" value="Write your wifi password...">
      <input type="submit" value="Save">
    </form>    
    </body>
    </html>
    )";

    server.send(200, "text/html", content);
}


void handlePostForm()
{
      String qsid = server.arg("ssid");
      String qpass = server.arg("password");
      String content;
      int statusCode;
  if(qsid != "" && qpass != ""){
      setCfg("newssid", "1234567890", 0);
      server.send(200, "text/html", "saced");
  }else{
    server.send(200, "text/html", "please fill all input");
  }
}

@d-a-v
Copy link
Collaborator

d-a-v commented Mar 6, 2021

OK to close this feature request per @Erriez's #7619 and #7629 ?

@Erriez
Copy link
Contributor

Erriez commented Mar 7, 2021

@d-a-v, yes you can close the feature requests.

@d-a-v d-a-v closed this as completed Mar 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants