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

Problems trying to reconnect to WIFI using NVS #304

Open
Ott-cop opened this issue Oct 2, 2023 · 14 comments
Open

Problems trying to reconnect to WIFI using NVS #304

Ott-cop opened this issue Oct 2, 2023 · 14 comments

Comments

@Ott-cop
Copy link

Ott-cop commented Oct 2, 2023

Good afternoon!

A few months ago I was trying to resolve an error that persists when using another NVS partition and the Wifi does not reconnect automatically. Only working after a manual reboot.
I'm using the standard Esp libs, following similar to the lib examples folder.

I (8345) wifi:new:<11,2>, old:<1,0>, ap:<255,255>, sta:<11,2>, prof:1 I (9095) wifi:state: init -> auth (b0) I (9095) wifi:state: auth -> init (8a0) I (9095) wifi:new:<11,0>, old:<11,2>, ap:<255,255>, sta:<11,2>, prof:1

Problem above.

I would appreciate any possible advice on how to solve this problem.

Thanks!

@Vollbrecht
Copy link
Collaborator

Well i think with the information you gave, one cant really help here. First why do you think the NVS has anything to do with your problem? And you are talking about few months ago? What does that mean? You are using esp-idf-* versions from a view months ago? You need to give some more information about your complete setup, what esp-idf versions are you using, how you assemble your project with regarding to wifi etc. Without that i think there is nothing really what others can help here if you are that vague.

@Ott-cop
Copy link
Author

Ott-cop commented Oct 3, 2023

Sorry, I really wasn't very clear.
About a few months ago, when I needed to increase the NVS functionalities in my project. This project works via WiFi and connected automatically without any problems when the power went out. When I added NVS specifically to store information in memory, it can no longer reconnect to the internet without first doing a "fake" manual boot to connect normally, and this is the problem.

The project was run using version 5.1, so with the errors happening I also tried running it on version 4.4 but without success. To execute the project, I am using an Esp32 Dev Kit.

For the code, I use an NVS partition to store the WIFI data and I created another partition (because I thought the error could be related to a conflict of writing to the same partition) to store values that must be remembered as soon as it boots.

I then used:

let nvs = EspDefaultNvsPartition::take().unwrap(); // for wifi
let nvs_custom_partition: EspNvsPartition<NvsCustom> = EspCustomNvsPartition::from("nvs_data"); // to the partition I created (file.csv)

Any additional information you need, I will send.

Thank you!

@Ott-cop Ott-cop closed this as completed Oct 3, 2023
@Ott-cop Ott-cop reopened this Oct 3, 2023
@ivmarkov
Copy link
Collaborator

ivmarkov commented Oct 3, 2023

Can you paste a short code snippet please which outlines what is supposed to work and doesn't? As in what methods exactly you are calling of the Wifi driver?

@Ott-cop
Copy link
Author

Ott-cop commented Oct 3, 2023

This is the part I create and call the driver:

fn main() -> anyhow::Result<()> { 
    //....more code..../ 
    let nvs_data_partition: EspNvsPartition<NvsCustom> = EspCustomNvsPartition::take("nvs_data").unwrap(); //Just by using the function to create it, it cannot reconnect every time on the internet, only a few times


    let sys_loop = EspSystemEventLoop::take()?;
    let nvs = EspDefaultNvsPartition::take()?; 

    let mut wifi = BlockingWifi::wrap(
        EspWifi::new(peripherals.modem, sys_loop.clone(), Some(nvs))?,
        sys_loop
    )?; 
     
    let mut server = block_on(create_server(&mut wifi))?;  // So I use it later like 
    server.fn_handler("/", Method::Get, move |mut req| {
        //....more code..../
    }
    //....more code..../ 
} 

async fn create_server(wifi: &mut BlockingWifi<EspWifi<'static>> ) -> anyhow::Result<EspHttpServer> {
    let wifi_configuration: Configuration = Configuration::Client(ClientConfiguration {
        ssid: SSID.into(),
        password: PASSWORD.into(),
        ..Default::default()
    });

    wifi.set_configuration(&wifi_configuration)?;
    wifi.start();
    info!("Wifi started");
    wifi.connect();
    info!("Wifi connected");

    wifi.wait_netif_up();
    info!("Wifi netif up");
    let server_configuration = esp_idf_svc::http::server::Configuration {
        stack_size: STACK_SIZE,
        session_timeout: Duration::from_secs(0),
        ..Default::default()
    };

    core::mem::forget(wifi);
    Ok(EspHttpServer::new(&server_configuration).unwrap())
}

The problem is that it is not reconnecting to the internet when I use NVS at the same time on a second boot:

I (944) esp_tcc_test: Wifi started
I (3354) wifi:new:<11,2>, old:<1,0>, ap:<255,255>, sta:<11,2>, prof:1
I (4094) wifi:state: init -> auth (b0)
I (4094) wifi:state: auth -> init (8a0)
I (4104) wifi:new:<11,0>, old:<11,2>, ap:<255,255>, sta:<11,2>, prof:1

The system appears to initialize the WIFI as an access point, which wouldn't be what I want.
The chip cannot reconnect to WIFI when doing a second boot. In which, for example, if there was a power outage, it would not be able to reconnect to the WIFI without the person restarting it manually so that it can reconnect.

Well, any more details you need I will send.

Thank you very much for now!

@Vollbrecht
Copy link
Collaborator

its not good practice to just use core::mem::forget on an object you want to possible use on the complete lifetime of your app.

Also note that the wifi example itself is only a basic setup. If you want to react on different states your wifi might be in, it is always recommended to listen to the specific wifi-events and act on them. You can find all wifi-events here. You can subscribe to this events through the sysloop.subscribe() method.

It looks rougly like that:

        
        sysloop.subscribe::<WifiEvent>(move |event| {
           if *event == WifiEvent::<SPECIFIC WIFI EVENT VARIANT>{
                // your event handling code
             }

you can get more fancy than that, using other eventloop mechanisms / notifications. But this will let you react on things on runetime. If you are in an undesirable state you can try to force a new connection or just reboot or do whatever to handle it.

Also if you are not using an async runtime / executor, try to use normal blocking rust calls to make your life easier at this stage.

@Ott-cop
Copy link
Author

Ott-cop commented Oct 4, 2023

Hello Vollbrecht

I sincerely appreciate the response!

Would there be a link to specific documentation on the method of use?
I made the changes as I specified, but I believe it was my error.

I believe this way is right, correct?

fn main() -> anyhow::Result<()> { 
    //....more code..../ 

    let mut wifi = BlockingWifi::wrap(
        EspWifi::new(peripherals.modem, sys_loop.clone(), Some(nvs))?,
        sys_loop.clone()
    )?; 
     
    let mut server = block_on(create_server(&mut wifi))?; 
    server.fn_handler("/", Method::Get, move |mut req| {
        //....more code..../
    }
    //....more code..../ 
    loop {
        println!("-------------------------------------------------------------------------------------");
        sys_loop.subscribe::<WifiEvent>(move |event| {
            if *event != WifiEvent::StaConnected {
                restart();
            }
        }).unwrap();
        sleep(Duration::from_millis(1000));
    }
} 

If it doesn't create a station, it will restart soon so that the next time it reconnects normally, right?

Thanks again for your time!

@Vollbrecht
Copy link
Collaborator

For an overall overview check out the official esp-idf documentation. Keep in mind that there are many EspWifi Events. You can find out what emits specific events by searching for "wifi_event" inside that linked documentation. You should not blindly just reboot on any wifievent you get that is not StaConnected.

@Ott-cop
Copy link
Author

Ott-cop commented Oct 6, 2023

Goodnight!

This is already a huge help, so I will focus more on these details.
Thank you both very much for the redirection and tips!

@embediver
Copy link
Contributor

Hello,
I am facing a similar behaviour where I get the same log messages as @Ott-cop when using wifi.

For me this behaviour seems to be triggered whenever the system resets while connected to a network.
I noticed it whenever I flashed the device and had it connected to wifi already (as its common when coding).
A ctrl-r reset in espflash monitor or a complete powercycle helps.

I noticed this across multiple projects utilizing the esp32c3 which use more or less the stock blocking wifi example with some gpio (spi, ...) and mqtt functionality added.

I haven't validated that this happens when the connection drops out, but had some devices randomly stuck at the connect step without a manual reset (probably my code panicked when the connection dropped and thus had a soft reset).

To be complete, following are the relevant dependencies and idf versions I use:

esp-idf-sys = { version = "0.33", default-features = false }
esp-idf-hal = { version = "0.41", optional = true, default-features = false }
esp-idf-svc = { version = "0.46", optional = true, default-features = false }
embedded-svc = { version = "0.25", optional = true, default-features = false }
embedded-hal = "1.0.0-alpha.10"
ESP_IDF_VERSION = "v4.4.5"

@vojty
Copy link

vojty commented Dec 21, 2023

I have a possibly related problem. The very first wifi.connect() (either after flashing or once I plug it into the power supply) fails and it always goes like this:

I (4094) wifi:state: init -> auth (b0)
I (4094) wifi:state: auth -> init (8a0)

The problem occurs both with and without NVS. The reset button or CTRL+R always fixes this. This didn't happen before with ESP-IDF v4. The same problem appears when the connection is lost so the following code for reconnecting didn't work:

    sysloop.subscribe(move |parsed_event: &WifiEvent| {
        if *parsed_event == WifiEvent::StaDisconnected {
            wifi.connect.unwrap();
        }
    })?;

I ended up with this hack, that works for both the initial connect and the reconnect:

pub trait WifiConnectFix {
    fn connect_with_retry(&mut self, retry_delay_ms: u64) -> anyhow::Result<()>;
}

pub fn sleep_ms(ms: u64) {
    thread::sleep(Duration::from_millis(ms));
}

impl WifiConnectFix for BlockingWifi<EspWifi<'_>> {
    fn connect_with_retry(&mut self, retry_delay_ms: u64) -> anyhow::Result<()> {
        loop {
            info!("Connecting wifi...");
            match self.connect() {
                Ok(()) => break,
                Err(e) => {
                    warn!(
                        "Wifi connect failed, reason {}, retrying in {}s",
                        e,
                        retry_delay_ms / 1000
                    );
                    sleep_ms(retry_delay_ms);
                    self.stop()?;
                    self.start()?;
                }
            }
        }

        info!("Waiting for DHCP lease...");

        self.wait_netif_up()?;
        Ok(())
    }
}

I'm using ESP-IDF v5.1.2 with these crates:

[dependencies]
anyhow = { version = "1.0.75", features = ["backtrace"] }
embedded-hal = "0.2.7"
embedded-svc= "0.26.2"
esp-idf-svc = "0.47.3"
log = "0.4.20"

[build-dependencies]
dotenv-build = "0.1.1"
embuild = "0.31.4"

@embediver
Copy link
Contributor

I observed the behaviour a little further and noticed this bug isn't consistent across different wifi networks.

As far as I can tell without testing it thoroughly, it works without problems on some networks, but has problems on other ones. (I have problems on my home network but not on the local hackerspaces network for example.)

@Ott-cop
Copy link
Author

Ott-cop commented Dec 21, 2023

Hello everybody.

I recently carried out some tests on how the chip works, and as @embediver said, it appears to work perfectly on some networks.
I've been testing some possible problems, and I believe I found a possible temporary solution. To do this, test by inserting each vTaskDelay as below between the data insertion function in NVS:

unsafe { esp_idf_svc::sys::vTaskDelay(10) };
let _ = nvs_data.clone().lock().unwrap().set_str(your_tag, data.trim_end_matches(char::from(0)));
unsafe { esp_idf_svc::sys::vTaskDelay(10) };

and set after the wifi instance as Power Save 0:

let mut wifi = AsyncWifi::wrap(
    EspWifi::new(peripherals.modem, sys_loop.clone(), Some(nvs)).unwrap(),
    sys_loop,
    imer_service
).unwrap();


// set Power Save 0 below
unsafe {
     esp_idf_svc::sys::esp_wifi_set_ps(esp_idf_svc::sys::wifi_ps_type_t_WIFI_PS_NONE);
} 

I was only able to "solve" it by making these additions to the code. I don't know if it would be ideal, but it's working.

@archifo
Copy link

archifo commented Mar 3, 2024

Hi,
I have a question related to the title of this thread but different from its contents.
I implement a very simple use case for wifi initialization :
1/ Attempt to connect to the Access Point which has been stored in NVS during the last boot session
2/ If unsuccessful, launch a SmartConfig session, waiting for my smartphone to provide the ssid and password with an ESP Touch app.
This is straightforward using the Arduino framework, especially phase 1 which consists of calling "Wifi.begin(), the equivalent of the Rust sequence init, start, connect, without argument instead of (ssid, password).
I tried in Rust to connect without calling set_configuration or calling it with empty SSID/PASS values, but it fails with an EspErrWifiSsid error.
Any idea to solve my problem ?

@ivmarkov
Copy link
Collaborator

Folks, can you try with esp-idf-svc from master?
I just fixed it to be compatible with ESP-IDF 5.3, but ALSO I noticed that two parameters in the Wifi configuration which existed before ESP IDF 5.3 were missing (incorrectly configured). This is now fixed as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Todo
Development

No branches or pull requests

6 participants