esp32: wifi provisioning via AP captive portal

Replace compile-time env!() wifi/server config with NVS-based
runtime provisioning. Boot checks NVS — if no config, starts
AP mode (KFrame-Setup) with DNS responder + HTTP config form.
WiFi failure clears config and reboots into setup mode.
This commit is contained in:
2026-06-19 01:38:48 +02:00
parent 1d7b5324d6
commit 4139330234
6 changed files with 389 additions and 15 deletions

View File

@@ -2,6 +2,7 @@ mod adapters;
mod boot;
mod config;
mod hal;
mod provisioning;
mod tasks;
use std::sync::mpsc;
@@ -10,10 +11,6 @@ use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::nvs::EspDefaultNvsPartition;
use log::info;
const WIFI_SSID: &str = env!("KFRAME_WIFI_SSID");
const WIFI_PASS: &str = env!("KFRAME_WIFI_PASS");
const SERVER_ADDR: &str = env!("KFRAME_SERVER_ADDR");
fn main() {
esp_idf_svc::sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();
@@ -24,7 +21,7 @@ fn main() {
let sysloop = EspSystemEventLoop::take().unwrap();
let nvs = EspDefaultNvsPartition::take().unwrap();
let display = hal::display::init(hal::display::DisplayHardware {
let mut display = hal::display::init(hal::display::DisplayHardware {
spi: peripherals.spi2,
sclk: peripherals.pins.gpio18.into(),
mosi: peripherals.pins.gpio23.into(),
@@ -34,11 +31,46 @@ fn main() {
});
info!("Display ready");
info!("Connecting WiFi...");
let _wifi = hal::wifi::init(peripherals.modem, sysloop, nvs, WIFI_SSID, WIFI_PASS)
.expect("WiFi init failed");
let (tx, rx) = mpsc::channel();
tasks::network::spawn(SERVER_ADDR.into(), tx);
tasks::render::run(config::SCREEN, display, rx);
match provisioning::read_config(nvs.clone()) {
Some(cfg) => run_station(peripherals.modem, sysloop, nvs, cfg, display),
None => {
info!("No config found, entering setup mode");
run_setup(peripherals.modem, sysloop, nvs, &mut display);
}
}
}
fn run_station(
modem: esp_idf_hal::modem::Modem<'static>,
sysloop: EspSystemEventLoop,
nvs: EspDefaultNvsPartition,
cfg: provisioning::DeviceConfig,
display: adapters::display::Esp32DisplayAdapter,
) {
info!("Connecting WiFi...");
match hal::wifi::init(modem, sysloop.clone(), nvs.clone(), &cfg.wifi_ssid, &cfg.wifi_pass) {
Ok(_wifi) => {
let (tx, rx) = mpsc::channel();
tasks::network::spawn(cfg.server_addr, tx);
tasks::render::run(config::SCREEN, display, rx);
}
Err(e) => {
info!("WiFi failed ({e}), clearing config and rebooting to setup mode");
provisioning::clear_config(nvs);
std::thread::sleep(std::time::Duration::from_secs(1));
unsafe { esp_idf_svc::sys::esp_restart(); }
}
}
}
fn run_setup(
modem: esp_idf_hal::modem::Modem<'static>,
sysloop: EspSystemEventLoop,
nvs: EspDefaultNvsPartition,
display: &mut adapters::display::Esp32DisplayAdapter,
) {
let _wifi = hal::wifi::init_ap(modem, sysloop, nvs.clone())
.expect("AP mode failed");
provisioning::portal::run_captive_portal(nvs, display);
}