Skip to content
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

for repair get error : No Credentials are Saved, skipping connect on esp32 #1483

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Rezaasghariir
Copy link

when i connect to ap after restart get No Credentials are Saved, skipping connect error but with this commit repair this.
and with CMakeLists.txt and component.mk file can use this component in arduino as esp-idf component in component folder

@tablatronix
Copy link
Collaborator

Whats the issue and or change here?

@tablatronix
Copy link
Collaborator

Does this add a wifi init check in wifi ssid to make sure its not garbage?

I wont merge it with the whitespace and formatting changes, feel free to fix the PR

@tablatronix tablatronix added the bug Validated BUG label Aug 30, 2022
@Rezaasghariir
Copy link
Author

Rezaasghariir commented Aug 30, 2022

Does this add a wifi init check in wifi ssid to make sure its not garbage?

after connect to ap after restart when run blow code :
esp_wifi_get_config(WIFI_IF_STA, &conf);
return ESP_ERR_WIFI_NOT_INIT for me. and return No Credentials are Saved, skipping connect. and Cannot connect to previously set AP.
other file (CMakeLists.txt and component.mk) is used went arduino as esp-idf component in ESP-IDF

@Erriez
Copy link

Erriez commented Sep 11, 2022

Basic Infos

Hardware

WiFimanager Branch/Release: master hash 7bdcfd

Esp8266/Esp32: ESP32
Hardware: ESP32 Devkit v1
Core Version: 2.04

Problem description

The debug output shows No Credentials are Saved, skipping connect on ESP32:

WiFi connect...
SSID: ⸮�⸮?�
*wm:[1] AutoConnect 
*wm:[1] No Credentials are Saved, skipping connect 
*wm:[2] enableConfigPortal: FALSE, skipping  
Failed. Retry in 10s...

When WiFi mode is not in WIFI_MODE_STA, the following code in WiFiManager.cpp function WiFi_SSID() returns garbage (not null terminated string). In this case the message No Credentials are Saved, skipping connect is printed:

wifi_config_t conf;
int err = esp_wifi_get_config(WIFI_IF_STA, &conf);

The returned error esp_wifi_get_config() is currently not handled in WiFi_SSID().

This can happen when the AP portal was started and changes to WIFI_MODE_STA mode at next reboot. As a result, it cannot connect to WiFi.

The suggested solution is to make sure that the ESP32 is in WIFI_MODE_STA before reading the SSID, for example in autoconnect(). Current workaround for the user is to use WiFi calls to connect to WiFi and not autoconnect().

Note: Forcing WiFi mode to WIFI_MODE_STA in function WiFi_SSID() in this pull request is not correct as the user can decide to use a different mode.

Testcase

Add the following testcode to a sketch to print incorrect SSID reads:

void wifiPrintStatus()
{
    Serial.print(F("WiFi mode: "));
    switch (WiFi.getMode()) {
        case WIFI_MODE_STA:
            Serial.println(F("STA"));
            break;
        case WIFI_MODE_AP:
            Serial.println(F("AP"));
            break;
        case WIFI_MODE_APSTA:
            Serial.println(F("APSTA"));
            break;
        default:
            Serial.println(F("ERROR"));
    }

    Serial.print(F("WiFi status: ")); 
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println(F("WiFi connected"));
        Serial.print(F("Local IP: ")); 
        Serial.println(WiFi.localIP());
    } else {
        Serial.println(F("WiFi not connected"));
    }

    // SSID returned string contains garbage when not in `WIFI_MODE_STA`. In this case cannot connect to WiFi via autoConnect().
    wifi_config_t conf;
    Serial.print(F("esp_wifi_get_config(): "));
    // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html
    Serial.println(esp_wifi_get_config(WIFI_IF_STA, &conf)); // 0 on success, else error
    Serial.print(F("SSID: "));
    Serial.println(String(reinterpret_cast<const char*>(conf.sta.ssid)));
}

Settings in IDE

Module: NodeMCU-32S

Additional libraries:

Sketch testcase

#include <EEPROM.h>
#include <WiFiManager.h>        // https://github.com/tzapu/WiFiManager master 7bdcfd

#define LED_PIN             LED_BUILTIN

#define WM_TITLE            "WiFiManager"
#define WM_AP_NAME          "ESP32AP"
#define WM_AP_PASSWORD      "changeme"
#define WM_CONNECT_TIMEOUT  20
#define WM_AUTO_CP          false
#define WM_DEBUG            true

#define EEPROM_SIZE                     512
#define DOUBLE_RESET_TIME_SEC           3
#define DOUBLE_RESET_EEPROM_ADDRESS     0x0100
#define DOUBLE_RESET_DETECT_FLAG_SET    0xD0D01234
#define DOUBLE_RESET_DETECT_FLAG_CLEAR  0xD0D04321

bool saveConfig = false;
bool saveParams = false;
bool doubleResetCheck = true;


bool isDoubleReset()
{
    uint32_t value;

    EEPROM.get(DOUBLE_RESET_EEPROM_ADDRESS, value);

    Serial.print(F("Read double reset flag: "));
    if (value == DOUBLE_RESET_DETECT_FLAG_SET) {
        Serial.println(F("SET"));
        return true;
    } else if (value == DOUBLE_RESET_DETECT_FLAG_CLEAR) {
        Serial.println(F("CLEAR"));
        return false;
    } else {
        Serial.println(F("INVALID"));
        return false;
    }
}

void doubleResetWrite(uint32_t value)
{
    uint32_t oldValue;
    
    EEPROM.get(DOUBLE_RESET_EEPROM_ADDRESS, oldValue);

    if (oldValue != value) {
        Serial.print(F("Write double reset flag: "));
        if (value == DOUBLE_RESET_DETECT_FLAG_SET) {
            Serial.println(F("SET"));
        } else if (value == DOUBLE_RESET_DETECT_FLAG_CLEAR) {
            Serial.println(F("CLEAR"));
            doubleResetCheck = false;
        } else {
            Serial.println(F("INVALID"));
            return;
        }

        EEPROM.put(DOUBLE_RESET_EEPROM_ADDRESS, value);
        EEPROM.commit();
    }
}

void doubleResetLoop()
{
    if (doubleResetCheck && (millis() > (DOUBLE_RESET_TIME_SEC * 1000))) {
        // Clear flag
        doubleResetWrite(DOUBLE_RESET_DETECT_FLAG_CLEAR);
    }
}

void espRestart()
{
    Serial.println(F("Restarting..."));
    delay(2000);
    ESP.restart();
    delay(5000);
}

void saveConfigCallback () 
{
    Serial.println("saveConfigCallback()");
    saveConfig = true;
}

void saveParamsCallback()
{
    Serial.println(F("saveParamsCallback()"));

    // Save parameters when exiting config portal
    saveParams = true;
}

void startWiFiConfigPortal()
{
    WiFiManager wm;

    // Start WiFi config portal
    Serial.println(F("Starting config portal (AP)..."));

    // Set debug
    wm.setDebugOutput(WM_DEBUG);

    // Set title config protal
    wm.setTitle(WM_TITLE);

    // Set config save callback
    //wm.setSaveConfigCallback(saveConfigCallback);

    // Set param save callback
    wm.setSaveParamsCallback(saveParamsCallback);

    // Always save parameters, even when WiFi connect failed
    wm.setBreakAfterConfig(true);

    // Automatically connect using saved credentials,
    // if connection fails, it starts an access point with the specified name ( "AutoConnectAP"),
    // if empty will auto generate SSID, if password is blank it will be anonymous AP (wm.autoConnect())
    // then goes into a blocking loop awaiting configuration and will return success result

    // Ignore false return value when aborting config portal
    (void)wm.startConfigPortal(WM_AP_NAME, WM_AP_PASSWORD);
}

void wifiConnect()
{
    wifi_config_t conf;
    WiFiManager wm;

    // Connect to WiFi
    Serial.print(F("WiFi connect..."));

    // Force station mode
    //WiFi.mode(WIFI_STA);

    esp_wifi_get_config(WIFI_IF_STA, &conf);
    Serial.print("config wifiConnect() before autoConnect(): ");
    Serial.println(String(reinterpret_cast<const char*>(conf.sta.ssid)));

    // Set debug output
    wm.setDebugOutput(WM_DEBUG);

    // Disable auto start config portal on WiFi connect failure
    wm.setEnableConfigPortal(WM_AUTO_CP);
  
    // Set connect timeout
    wm.setConnectTimeout(WM_CONNECT_TIMEOUT);

    // Connect to WiFi access point
    while (!wm.autoConnect()) {
        Serial.println(F("Failed. Retry in 10s..."));
        delay(10000);
        Serial.print(F("WiFi connect..."));
    }

    esp_wifi_get_config(WIFI_IF_STA, &conf);
    Serial.print("config wifiConnect() after autoConnect(): ");
    Serial.println(String(reinterpret_cast<const char*>(conf.sta.ssid)));

    // WiFi connected
    Serial.print(F("Connected\nlocal IP: ")); 
    Serial.println(WiFi.localIP());
}

void wifiDisconnect()
{
    WiFi.mode(WIFI_OFF);
}

void setup() 
{
    // Initialize LED
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    // Initialize serial
    Serial.begin(115200); 
    Serial.println(F("\nErriez double reset example")); 

    // Initialize EEPROM
    if (!EEPROM.begin(EEPROM_SIZE)) {
        Serial.println("EEPROM init error");
        espRestart();
    }

    // Detect double reset
    if (isDoubleReset()) {
        // Clear double reset flag
        doubleResetWrite(DOUBLE_RESET_DETECT_FLAG_CLEAR);
    
        // Start AP config
        startWiFiConfigPortal();

        // Restart ESP
        espRestart();
    }

    // Set double reset flag
    doubleResetWrite(DOUBLE_RESET_DETECT_FLAG_SET);

    // Connect to WiFi
    wifiConnect();

    digitalWrite(LED_PIN, LOW);
}

void loop() 
{
    doubleResetLoop();

    if (WiFi.status() == WL_CONNECTED) {
        Serial.println(F("WiFi connected"));
    } else {
        Serial.println(F("WiFi not connected"));
    }

    digitalWrite(LED_PIN, HIGH);
    delay(2000);
    digitalWrite(LED_PIN, LOW);
    delay(2000);
}

@Erriez
Copy link

Erriez commented Sep 12, 2022

Does anyone know why the WiFi mode is forced to WIFI_OFF in autoConnect() for ESP32 when a hostname is set? This is the root cause of the problem:

WiFi.mode(WIFI_OFF);

It does not make sense to call WiFi.mode(WIFI_STA); before autoConnect() as the WiFi is always disabled in autoConnect() and not restored to STA mode. Reading SSID will fail.

Disabling WiFi also slows down the WiFi connection speed compared with:

void wifiConnectFast()
{
    // Test case by using `WiFi` is faster than wm.autoConnect() as it disables WiFi first.
    Serial.println(F("Connecting to WiFi"));
    WiFi.mode(WIFI_STA);
    WiFi.persistent(true);
    WiFi.begin();
    while (WiFi.status() != WL_CONNECTED) {
        delay(100);
    }
    Serial.println(WiFi.localIP());
}

@Erriez
Copy link

Erriez commented Sep 12, 2022

Bug in:

if(_hostname){

Function setHostname() is not called (no hostname configured in STA mode) and always disables WiFi in autoConnect() as the String hostname if statement is incorrect:

Testcase:

void setup() 
{
    // Initialize serial
    Serial.begin(115200); 
    Serial.println(F("\nErriez String example"));

    // Create string object
    String _hostname;

    // Print hostname (which is empty)
    Serial.println(F("Hostname: ");
    Serial.println(_hostname);

    // Perform incorrect comparison
    if (_hostname) {
        // Always true
        Serial.println("true");
    } else {
        Serial.println("false");
    }

Bugfix:

-if (_hostname) {
+if (!_hostname.isEmpty()) {

or:

-if (_hostname) {
+if (_hostname != "") {

@tablatronix 94bb903

@Erriez
Copy link

Erriez commented Sep 12, 2022

Issue #1490 with pull request #1491 replaces this PR.

@tablatronix
Copy link
Collaborator

tablatronix commented Sep 12, 2022

Sorry I haven't fixed this yet, I discover major bugs in esp32 while working on this and after the hostname fix that sidetracked me

@tablatronix
Copy link
Collaborator

I removed this check entirely, it was intended to speed up connections, until I find a better way to init wifi It will remain off.
and the method to check wont work.

I am adding a passive check using events for init checking then will look into startup speed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Validated BUG
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants