not working wip of station mode

This commit is contained in:
2025-09-25 22:32:10 +02:00
parent e20b474dfd
commit 336961f0a0
3 changed files with 150 additions and 118 deletions

View File

@@ -1,6 +1,6 @@
use crate::bail; use crate::bail;
use crate::config::{NetworkConfig, PlantControllerConfig}; use crate::config::{NetworkConfig, PlantControllerConfig};
use crate::hal::PLANT_COUNT; use crate::hal::{PLANT_COUNT, TIME_ACCESS};
use crate::log::{LogMessage, LOG_ACCESS}; use crate::log::{LogMessage, LOG_ACCESS};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::Serialize; use serde::Serialize;
@@ -14,8 +14,11 @@ use alloc::borrow::ToOwned;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::net::{IpAddr, Ipv4Addr}; use core::net::{IpAddr, Ipv4Addr};
use core::str::FromStr; use core::str::FromStr;
use core::sync::atomic::Ordering;
use core::sync::atomic::Ordering::Relaxed;
use edge_dhcp::io::server::run;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_net::{Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4}; use embassy_net::{DhcpConfig, Ipv4Cidr, Runner, Stack, StackResources, StaticConfigV4};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::mutex::Mutex; use embassy_sync::mutex::Mutex;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
@@ -28,13 +31,11 @@ use esp_hal::rtc_cntl::sleep::RtcSleepConfig;
use esp_hal::system::software_reset; use esp_hal::system::software_reset;
use esp_println::println; use esp_println::println;
use esp_storage::FlashStorage; use esp_storage::FlashStorage;
use esp_wifi::wifi::{ use esp_wifi::wifi::{AccessPointConfiguration, AccessPointInfo, AuthMethod, ClientConfiguration, Configuration, Interfaces, ScanConfig, ScanTypeConfig, WifiController, WifiDevice, WifiState};
AccessPointConfiguration, AccessPointInfo, Configuration, Interfaces, ScanConfig,
ScanTypeConfig, WifiController, WifiDevice,
};
use littlefs2::fs::Filesystem; use littlefs2::fs::Filesystem;
use littlefs2_core::{FileType, PathBuf, SeekFrom}; use littlefs2_core::{FileType, PathBuf, SeekFrom};
use log::info; use log::info;
use portable_atomic::AtomicBool;
#[esp_hal::ram(rtc_fast, persistent)] #[esp_hal::ram(rtc_fast, persistent)]
static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT]; static mut LAST_WATERING_TIMESTAMP: [i64; PLANT_COUNT] = [0; PLANT_COUNT];
@@ -75,7 +76,8 @@ pub struct Esp<'a> {
pub fs: Arc<Mutex<CriticalSectionRawMutex, Filesystem<'static, LittleFs2Filesystem>>>, pub fs: Arc<Mutex<CriticalSectionRawMutex, Filesystem<'static, LittleFs2Filesystem>>>,
pub rng: Rng, pub rng: Rng,
//first starter (ap or sta will take these) //first starter (ap or sta will take these)
pub interfaces: Option<Interfaces<'static>>, pub interface_sta: Option<WifiDevice<'static>>,
pub interface_ap: Option<WifiDevice<'static>>,
pub controller: Arc<Mutex<CriticalSectionRawMutex, WifiController<'static>>>, pub controller: Arc<Mutex<CriticalSectionRawMutex, WifiController<'static>>>,
//only filled, if a useable mqtt client with working roundtrip could be established //only filled, if a useable mqtt client with working roundtrip could be established
@@ -288,7 +290,7 @@ impl Esp<'_> {
} }
} }
pub(crate) async fn wifi_ap(&mut self) -> FatResult<Stack<'static>> { pub(crate) async fn wifi_ap(&mut self, fallback: bool) -> FatResult<Stack<'static>> {
let ssid = match self.load_config().await { let ssid = match self.load_config().await {
Ok(config) => config.network.ap_ssid.as_str().to_string(), Ok(config) => config.network.ap_ssid.as_str().to_string(),
Err(_) => "PlantCtrl Emergency Mode".to_string(), Err(_) => "PlantCtrl Emergency Mode".to_string(),
@@ -296,7 +298,7 @@ impl Esp<'_> {
let spawner = Spawner::for_current_executor().await; let spawner = Spawner::for_current_executor().await;
let device = self.interfaces.take().unwrap().ap; let device = self.interface_ap.take().unwrap();
let gw_ip_addr_str = "192.168.71.1"; let gw_ip_addr_str = "192.168.71.1";
let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip"); let gw_ip_addr = Ipv4Addr::from_str(gw_ip_addr_str).expect("failed to parse gateway ip");
@@ -308,6 +310,86 @@ impl Esp<'_> {
let seed = (self.rng.random() as u64) << 32 | self.rng.random() as u64; let seed = (self.rng.random() as u64) << 32 | self.rng.random() as u64;
println!("init secondary stack");
// Init network stack
let (stack, runner) = embassy_net::new(
device,
config,
mk_static!(StackResources<4>, StackResources::<4>::new()),
seed,
);
let stack = mk_static!(Stack, stack);
let client_config = Configuration::AccessPoint(AccessPointConfiguration {
ssid: ssid.clone(),
..Default::default()
});
println!("stop old");
self.controller.lock().await.stop()?;
self.controller
.lock()
.await
.set_configuration(&client_config)?;
println!("start new");
self.controller.lock().await.start()?;
println!("start net task");
spawner.spawn(net_task(runner)).ok();
println!("run dhcp");
spawner.spawn(run_dhcp(stack.clone(), gw_ip_addr_str)).ok();
loop {
println!("waiting for wifi ap link up");
if stack.is_link_up() {
break;
}
Timer::after(Duration::from_millis(500)).await;
}
while !stack.is_config_up() {
println!("waiting for wifi ap config up");
Timer::after(Duration::from_millis(100)).await
}
println!(
"Connect to the AP `${ssid}` and point your browser to http://{gw_ip_addr_str}/"
);
stack
.config_v4()
.inspect(|c| println!("ipv4 config: {c:?}"));
Ok(stack.clone())
}
pub(crate) async fn wifi(&mut self, network_config: &NetworkConfig) -> FatResult<Stack<'static>> {
esp_wifi::wifi_set_log_verbose();
let ssid = network_config.ssid.clone();
match &ssid {
Some(ssid) => {
if ssid.is_empty() {
bail!("Wifi ssid was empty")
}
}
None => {
bail!("Wifi ssid was empty")
}
}
let ssid = ssid.unwrap().to_string();
info!("attempting to connect wifi {ssid}");
let password = match network_config.password {
Some(ref password) => password.to_string(),
None => "".to_string(),
};
let max_wait = network_config.max_wait;
let spawner = Spawner::for_current_executor().await;
let device = self.interface_sta.take().unwrap();
let config = embassy_net::Config::dhcpv4(DhcpConfig::default());
let seed = (self.rng.random() as u64) << 32 | self.rng.random() as u64;
// Init network stack // Init network stack
let (stack, runner) = embassy_net::new( let (stack, runner) = embassy_net::new(
device, device,
@@ -317,28 +399,58 @@ impl Esp<'_> {
); );
let stack = mk_static!(Stack, stack); let stack = mk_static!(Stack, stack);
spawner let client_config = Configuration::Client(ClientConfiguration {
.spawn(connection(self.controller.clone(), ssid.to_owned())) ssid,
.ok(); bssid: None,
auth_method: AuthMethod::None,
password,
channel: None,
});
self.controller
.lock()
.await
.set_configuration(&client_config)?;
spawner.spawn(net_task(runner)).ok(); spawner.spawn(net_task(runner)).ok();
spawner.spawn(run_dhcp(stack.clone(), gw_ip_addr_str)).ok(); self.controller.lock().await.start_async().await?;
let timeout = TIME_ACCESS.get().await.current_time_us() + max_wait as u64 * 1000;
loop { loop {
if stack.is_link_up() { let state = esp_wifi::wifi::ap_state();
break; println!("waiting wifi sta ready {:?}", state);
match state{
WifiState::StaStarted => {
self.controller.lock().await.connect()?;
break;
}
WifiState::StaConnected => {}
WifiState::StaDisconnected => {}
WifiState::StaStopped => {}
WifiState::ApStarted => {}
WifiState::ApStopped => {}
WifiState::Invalid => {}
} }
if TIME_ACCESS.get().await.current_time_us() > timeout {
bail!("Timeout waiting for wifi link up")
}
}
while !stack.is_link_up() {
if TIME_ACCESS.get().await.current_time_us() > timeout {
bail!("Timeout waiting for wifi link up")
}
println!("waiting for wifi link up");
Timer::after(Duration::from_millis(500)).await; Timer::after(Duration::from_millis(500)).await;
} }
while !stack.is_config_up() { while !stack.is_config_up() {
if TIME_ACCESS.get().await.current_time_us() > timeout {
bail!("Timeout waiting for wifi config up")
}
println!("waiting for wifi config up");
Timer::after(Duration::from_millis(100)).await Timer::after(Duration::from_millis(100)).await
} }
println!(
"Connect to the AP `${ssid}` and point your browser to http://{gw_ip_addr_str}/"
);
stack
.config_v4()
.inspect(|c| println!("ipv4 config: {c:?}"));
Ok(stack.clone()) Ok(stack.clone())
} }
@@ -370,76 +482,6 @@ impl Esp<'_> {
//}; //};
} }
pub(crate) async fn wifi(&mut self, network_config: &NetworkConfig) -> FatResult<IpInfo> {
let _ssid = network_config.ssid.clone();
match &_ssid {
Some(ssid) => {
if ssid.is_empty() {
bail!("Wifi ssid was empty")
}
}
None => {
bail!("Wifi ssid was empty")
}
}
let _ssid = _ssid.unwrap();
let _password = network_config.password.clone();
let _max_wait = network_config.max_wait;
bail!("todo")
// match password {
// Some(pw) => {
// //TODO expect error due to invalid pw or similar! //call this during configuration and check if works, revert to config mode if not
// self.wifi_driver.set_configuration(&Configuration::Client(
// ClientConfiguration {
// ssid,
// password: pw,
// ..Default::default()
// },
// ))?;
// }
// None => {
// self.wifi_driver.set_configuration(&Configuration::Client(
// ClientConfiguration {
// ssid,
// auth_method: AuthMethod::None,
// ..Default::default()
// },
// ))?;
// }
// }
//
// self.wifi_driver.start()?;
// self.wifi_driver.connect()?;
//
// let delay = Delay::new_default();
// let mut counter = 0_u32;
// while !self.wifi_driver.is_connected()? {
// delay.delay_ms(250);
// counter += 250;
// if counter > max_wait {
// //ignore these errors, Wi-Fi will not be used this
// self.wifi_driver.disconnect().unwrap_or(());
// self.wifi_driver.stop().unwrap_or(());
// bail!("Did not manage wifi connection within timeout");
// }
// }
// log::info!("Should be connected now, waiting for link to be up");
//
// while !self.wifi_driver.is_up()? {
// delay.delay_ms(250);
// counter += 250;
// if counter > max_wait {
// //ignore these errors, Wi-Fi will not be used this
// self.wifi_driver.disconnect().unwrap_or(());
// self.wifi_driver.stop().unwrap_or(());
// bail!("Did not manage wifi connection within timeout");
// }
// }
// //update freertos registers ;)
// let address = self.wifi_driver.sta_netif().get_ip_info()?;
// log(LogMessage::WifiInfo, 0, 0, "", &format!("{address:?}"));
// anyhow::Ok(address)
}
pub(crate) async fn load_config(&mut self) -> FatResult<PlantControllerConfig> { pub(crate) async fn load_config(&mut self) -> FatResult<PlantControllerConfig> {
let cfg = PathBuf::try_from(CONFIG_FILE).unwrap(); let cfg = PathBuf::try_from(CONFIG_FILE).unwrap();
let data = self.fs.lock().await.read::<4096>(&cfg)?; let data = self.fs.lock().await.read::<4096>(&cfg)?;
@@ -796,25 +838,8 @@ async fn run_dhcp(stack: Stack<'static>, gw_ip_addr: &'static str) {
} }
} }
#[embassy_executor::task]
async fn connection(
controller: Arc<Mutex<CriticalSectionRawMutex, WifiController<'static>>>,
ssid: String,
) {
let client_config = Configuration::AccessPoint(AccessPointConfiguration {
ssid: ssid.clone(),
..Default::default()
});
controller
.lock()
.await
.set_configuration(&client_config)
.unwrap();
controller.lock().await.start_async().await.unwrap();
println!("Wifi started!");
}
#[embassy_executor::task] #[embassy_executor::task(pool_size = 2)]
async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
runner.run().await runner.run().await
} }

View File

@@ -381,11 +381,14 @@ impl PlantHal {
lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"), lfs2Filesystem::mount(alloc, lfs2filesystem).expect("Could not mount lfs2 filesystem"),
)); ));
let ap = interfaces.ap;
let sta = interfaces.sta;
let mut esp = Esp { let mut esp = Esp {
fs, fs,
rng, rng,
controller: Arc::new(Mutex::new(controller)), controller: Arc::new(Mutex::new(controller)),
interfaces: Some(interfaces), interface_sta : Some(sta),
interface_ap : Some(ap),
boot_button, boot_button,
mqtt_client: None, mqtt_client: None,
ota, ota,

View File

@@ -234,7 +234,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
{ {
info!("No wifi configured, starting initial config mode"); info!("No wifi configured, starting initial config mode");
let stack = board.board_hal.get_esp().wifi_ap().await?; let stack = board.board_hal.get_esp().wifi_ap(false).await?;
let reboot_now = Arc::new(AtomicBool::new(false)); let reboot_now = Arc::new(AtomicBool::new(false));
println!("starting webserver"); println!("starting webserver");
@@ -243,8 +243,6 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
wait_infinity(board, WaitType::MissingConfig, reboot_now.clone()).await; wait_infinity(board, WaitType::MissingConfig, reboot_now.clone()).await;
} }
info!("attempting to connect wifi ");
let mut stack = Option::None; let mut stack = Option::None;
let network_mode = if board.board_hal.get_config().network.ssid.is_some() { let network_mode = if board.board_hal.get_config().network.ssid.is_some() {
try_connect_wifi_sntp_mqtt(&mut board, *&mut stack).await try_connect_wifi_sntp_mqtt(&mut board, *&mut stack).await
@@ -261,7 +259,7 @@ async fn safe_main(spawner: Spawner) -> FatResult<()> {
let res = { let res = {
let esp = board.board_hal.get_esp(); let esp = board.board_hal.get_esp();
esp.wifi_ap().await esp.wifi_ap(true).await
}; };
match res { match res {
@@ -898,10 +896,16 @@ async fn publish_firmware_info(
let _ = esp.mqtt_publish("/state", "online".as_bytes()).await; let _ = esp.mqtt_publish("/state", "online".as_bytes()).await;
} }
async fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>, stack_store:Option<Stack<'_>>) -> NetworkMode { async fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<'static, CriticalSectionRawMutex, HAL<'static>>, mut stack_store:Option<Stack<'_>>) -> NetworkMode {
let nw_conf = &board.board_hal.get_config().network.clone(); let nw_conf = &board.board_hal.get_config().network.clone();
match board.board_hal.get_esp().wifi(nw_conf).await { match board.board_hal.get_esp().wifi(nw_conf).await {
Ok(ip_info) => { Ok(stack) => {
stack_store = Some(stack);
loop {
println!("wifi stuff");
Timer::after_millis(1000).await;
}
let sntp_mode: SntpMode = match board.board_hal.get_esp().sntp(1000 * 10).await { let sntp_mode: SntpMode = match board.board_hal.get_esp().sntp(1000 * 10).await {
Ok(new_time) => { Ok(new_time) => {
info!("Using time from sntp"); info!("Using time from sntp");
@@ -932,7 +936,7 @@ async fn try_connect_wifi_sntp_mqtt(board: &mut MutexGuard<'static, CriticalSect
NetworkMode::WIFI { NetworkMode::WIFI {
sntp: sntp_mode, sntp: sntp_mode,
mqtt: mqtt_connected, mqtt: mqtt_connected,
ip_address: ip_info.ip.to_string(), ip_address: stack.hardware_address().to_string(),
} }
} }
Err(err) => { Err(err) => {