From 66b711f6b0d4dfa78dbeaa537644e80275abd997 Mon Sep 17 00:00:00 2001 From: rhetenor Date: Sun, 13 Sep 2026 14:04:20 +0200 Subject: [PATCH] wifi: implement station change and connect --- src/bin/main.rs | 4 +- src/network/wifi.rs | 78 ++++++++++++++++++++++------ src/peripherals/storage/cardstore.rs | 12 ++--- src/peripherals/storage/wifistore.rs | 22 ++++---- 4 files changed, 83 insertions(+), 33 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 4e37738..0f4e105 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -130,10 +130,8 @@ async fn main(spawner: Spawner) { )); let wifi_store = WifiStore::new(nvs.clone()).await.expect("Could not initialize WiFi store"); - let init_credentials = Wifi::initialize_credentials(&wifi_store).await.expect("Could not get init WiFi credentials"); - - let wifi = Wifi::new(esp_peripherals.WIFI, init_credentials).expect("Could not initialize WiFi"); + let wifi = Wifi::new(esp_peripherals.WIFI, init_credentials).await.expect("Could not initialize WiFi"); let card_store = CardStore::new(nvs.clone()) .await diff --git a/src/network/wifi.rs b/src/network/wifi.rs index 649e996..a742556 100644 --- a/src/network/wifi.rs +++ b/src/network/wifi.rs @@ -1,4 +1,6 @@ use crate::Mutex; +use esp_radio::wifi::sta::StationConfig; +use esp_radio::wifi::Config; use crate::alloc::string::ToString; use crate::Signal; use crate::navigation::outputs::Outputs; @@ -23,9 +25,8 @@ pub static WIFI_CREDENTIALS: Signal = Signal::new(); #[derive(Debug)] pub struct Wifi { - pub controller: WifiController<'static>, - pub interfaces: wifi::Interfaces<'static>, - pub credentials: WifiCredentials, + controller: WifiController<'static>, + interfaces: wifi::Interfaces<'static>, } #[derive(Debug)] @@ -60,30 +61,65 @@ impl From for WifiError { } impl Wifi { - pub fn new( + pub async fn new( wifi: esp_hal::peripherals::WIFI<'static>, - credentials: WifiCredentials + credentials: Option ) -> Result { let wifi = wifi::new(wifi, Default::default())?; - Ok(Self { + let mut instance = Self { controller: wifi.0, - interfaces: wifi.1, - credentials - }) + interfaces: wifi.1 + }; + + if let Some(creds) = credentials { + instance.set_station(creds).await?; + } + + Ok(instance) } + // get wifi credentials from env WIFI_SSID; WIFI_PASS (priority) or storage pub async fn initialize_credentials( wifi_store: &WifiStore, - ) -> Result { - let stored_credentials = wifi_store.load_credentials().await?; - let ssid = option_env!("WIFI_SSID").map_or(stored_credentials.ssid, |v| v.to_string()); - let pass = option_env!("WIFI_PASS").map_or(stored_credentials.pass, |v| v.to_string()); + ) -> Result, WifiError> { + let option_stored_credentials = wifi_store.load_credentials().await?; + + let env_ssid = option_env!("WIFI_SSID"); + let env_pass = option_env!("WIFI_PASS"); + + if env_ssid.is_none() && option_stored_credentials.is_none() { + log::info!("no initial wifi credentials"); + return Ok(None); + } + + let stored_credentials = option_stored_credentials.expect("checked value before"); + + let ssid = env_ssid.map_or(stored_credentials.ssid, |v| v.to_string()); + let pass = env_pass.map_or(stored_credentials.pass, |v| v.to_string()); log::info!("initial wifi credentials:\nssid:{ssid}, pass:{pass}"); - Ok(WifiCredentials {ssid, pass}) + + Ok(Some(WifiCredentials {ssid, pass})) } + pub async fn connect(&mut self) -> Result<(), WifiError>{ + log::info!("connecting wifi..."); + + let stationinfo = self.controller.connect_async().await?; + + log::info!("connected to {}", stationinfo.ssid.as_str()); + + Ok(()) + } + + pub async fn set_station(&mut self, credentials: WifiCredentials) -> Result<(), WifiError> { + let station_config = StationConfig::default().with_ssid(credentials.ssid).with_password(credentials.pass); + self.controller.set_config(&Config::Station(station_config))?; + Ok(()) + } + + #[cfg(feature = "wokwi")] pub async fn setup( wifi: esp_hal::peripherals::WIFI<'static>, @@ -123,9 +159,10 @@ impl Wifi { } } + + #[embassy_executor::task] pub async fn wait_for_wifi_credentials(_outputs: &'static Mutex, peripherals: &'static Peripherals) { - loop { log::info!("Waiting for new WiFi credentials"); let credentials = WIFI_CREDENTIALS.wait().await; @@ -138,6 +175,17 @@ pub async fn wait_for_wifi_credentials(_outputs: &'static Mutex, periph log::info!("Saved new WiFi credentials. Restarting WiFi"); + let mut wifi = peripherals.wifi.lock().await; + + if let Err(err) = wifi.set_station(credentials).await { + log::error!("Error setting new wifi station: {err}"); + continue; + } + + if let Err(err) = wifi.connect().await { + log::error!("Error connecting to wifi: {err}"); + continue; + } } } diff --git a/src/peripherals/storage/cardstore.rs b/src/peripherals/storage/cardstore.rs index 843bfdd..d81492e 100644 --- a/src/peripherals/storage/cardstore.rs +++ b/src/peripherals/storage/cardstore.rs @@ -60,7 +60,7 @@ pub struct CardStoreMetaData { impl CardStoreMetaData { fn new(creation_date: u64) -> Self { Self { - creation_date: creation_date, + creation_date, last_read_date: creation_date, read_count: 0, } @@ -94,18 +94,18 @@ impl CardStore { match nvs_lock.get::(&NVS_NAMESPACE_CARDSTORE, &NVS_CARDSTORE_INITIALIZED_KEY) { Ok(initialized) => { log::debug!("initialization_check: initialized {initialized:?}"); - return Ok(true); + Ok(true) } Err(esp_nvs::error::Error::NamespaceNotFound) => { log::debug!("initialization_check: error: namespace not found"); - return Ok(false); + Ok(false) } Err(esp_nvs::error::Error::KeyNotFound) => { log::debug!("initialization_check: error: key not found"); - return Ok(false); + Ok(false) } - Err(error) => return Err(error.into()), - }; + Err(error) => Err(error.into()), + } } // initializing cardstore with 0 cards, so that all namespaces exist and there diff --git a/src/peripherals/storage/wifistore.rs b/src/peripherals/storage/wifistore.rs index 12fa043..02fc407 100644 --- a/src/peripherals/storage/wifistore.rs +++ b/src/peripherals/storage/wifistore.rs @@ -55,18 +55,18 @@ impl WifiStore { match nvs_lock.get::(&NVS_NAMESPACE_WIFI, &NVS_WIFI_INITIALIZED_KEY) { Ok(initialized) => { log::debug!("initialization_check: initialized {initialized:?}"); - return Ok(true); + Ok(true) } Err(esp_nvs::error::Error::NamespaceNotFound) => { log::debug!("initialization_check: error: namespace not found"); - return Ok(false); + Ok(false) } Err(esp_nvs::error::Error::KeyNotFound) => { log::debug!("initialization_check: error: key not found"); - return Ok(false); + Ok(false) } - Err(error) => return Err(error.into()), - }; + Err(error) => Err(error.into()), + } } async fn initialize(nvs: &Mutex) -> Result<(), WifiStoreError> { @@ -74,14 +74,14 @@ impl WifiStore { let mut nvs_lock = nvs.lock().await; - log::debug!("initialization: write dummy ssid"); + log::debug!("initialization: write empty ssid"); nvs_lock.set::<&str>( &NVS_NAMESPACE_WIFI, &NVS_WIFI_SSID_KEY, "" )?; - log::debug!("initialization: write dummy pass"); + log::debug!("initialization: write empty pass"); nvs_lock.set::<&str>( &NVS_NAMESPACE_WIFI, &NVS_WIFI_PASS_KEY, @@ -99,18 +99,22 @@ impl WifiStore { Ok(()) } - pub async fn load_credentials(&self) -> Result { + pub async fn load_credentials(&self) -> Result, WifiStoreError> { log::debug!("loading wifi credentials"); log::debug!("loading ssid"); let mut nvs_lock = self.nvs.lock().await; let ssid = nvs_lock.get::(&NVS_NAMESPACE_WIFI, &NVS_WIFI_SSID_KEY)?; + if ssid.is_empty() { + return Ok(None); + } log::debug!("ssid: {ssid}"); log::debug!("loading pass"); let pass = nvs_lock.get::(&NVS_NAMESPACE_WIFI, &NVS_WIFI_PASS_KEY)?; + log::debug!("pass: {pass}"); - Ok(WifiCredentials{ssid, pass}) + Ok(Some(WifiCredentials{ssid, pass})) } pub async fn save_credentials(&self, credentials: &WifiCredentials) -> Result<(), WifiStoreError> {