📟 pmme-device: BT_NIMBLE support for wifi provisioning
This commit is contained in:
parent
9d5b9366d5
commit
4e07dbb461
@ -19,8 +19,7 @@ opt-level = "z"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# experimental = ["esp-idf-svc/experimental"]
|
||||
experimental = ["esp-idf-svc/experimental"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
@ -28,7 +27,6 @@ esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-
|
||||
anyhow = "1.0.98"
|
||||
embedded-graphics = "0.8.1"
|
||||
ssd1306 = "0.10.0"
|
||||
# esp-idf-hal = { version = "0.45.2", features = ["std"] }
|
||||
|
||||
[build-dependencies]
|
||||
embuild = "0.33"
|
||||
|
@ -1,5 +1,13 @@
|
||||
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
|
||||
# CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
# CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="./partitions.csv"
|
||||
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_WIFI_PROV_SCHEME_BLE=y
|
||||
# CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
|
||||
# CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
|
||||
|
||||
# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
|
||||
# This allows to use 1 ms granularity for thread sleeps (10 ms by default).
|
||||
|
@ -1,13 +1,23 @@
|
||||
use crate::Pms7003Data;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use log::info;
|
||||
use anyhow::{anyhow, Result};
|
||||
use log::info;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use embedded_graphics::{Drawable, image::{Image, ImageRaw}, mono_font::{ascii::FONT_10X20, MonoTextStyle}, pixelcolor::BinaryColor, prelude::Point, text::Text};
|
||||
use embedded_graphics::draw_target::DrawTarget;
|
||||
use embedded_graphics::{
|
||||
image::{Image, ImageRaw},
|
||||
mono_font::{ascii::FONT_10X20, MonoTextStyle},
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::Point,
|
||||
text::Text,
|
||||
Drawable,
|
||||
};
|
||||
use esp_idf_svc::hal::{delay::FreeRtos, i2c::I2cDriver};
|
||||
use ssd1306::{mode::DisplayConfig, prelude::DisplayRotation, size::DisplaySize128x64, I2CDisplayInterface, Ssd1306};
|
||||
use ssd1306::{
|
||||
mode::DisplayConfig, prelude::DisplayRotation, size::DisplaySize128x64, I2CDisplayInterface,
|
||||
Ssd1306,
|
||||
};
|
||||
|
||||
pub fn oled_task(pm_data: Arc<Mutex<Pms7003Data>>, i2c: I2cDriver) -> Result<()> {
|
||||
info!("Staring OLED Task");
|
||||
@ -41,9 +51,7 @@ pub fn oled_task(pm_data: Arc<Mutex<Pms7003Data>>, i2c: I2cDriver) -> Result<()>
|
||||
.map_err(|e| anyhow!("Could not draw text! {:?}", e))?;
|
||||
display
|
||||
.flush()
|
||||
.map_err(|e| {
|
||||
anyhow!("Could not flush display! {:?}", e)
|
||||
})?;
|
||||
.map_err(|e| anyhow!("Could not flush display! {:?}", e))?;
|
||||
FreeRtos::delay_ms(500);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
pub mod wifi;
|
||||
pub mod sensors;
|
||||
pub mod display;
|
||||
pub mod sensors;
|
||||
pub mod wifi;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Pms7003Data {
|
||||
|
@ -1,15 +1,23 @@
|
||||
use std::{sync::{Arc, Mutex}, thread};
|
||||
use anyhow::Result;
|
||||
|
||||
use esp_idf_svc::hal::{
|
||||
gpio,
|
||||
i2c::{I2cConfig, I2cDriver},
|
||||
peripherals::Peripherals,
|
||||
prelude::FromValueType,
|
||||
uart::{config, UartDriver},
|
||||
units::Hertz,
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
};
|
||||
use pmme_device::{display::oled_task, sensors::pm_sensor_task, Pms7003Data};
|
||||
|
||||
use esp_idf_svc::{
|
||||
eventloop::EspSystemEventLoop,
|
||||
hal::{
|
||||
gpio,
|
||||
i2c::{I2cConfig, I2cDriver},
|
||||
peripherals::Peripherals,
|
||||
prelude::FromValueType,
|
||||
uart::{self, UartDriver},
|
||||
units::Hertz,
|
||||
},
|
||||
log::EspLogger,
|
||||
nvs::EspDefaultNvsPartition,
|
||||
};
|
||||
use pmme_device::{display::oled_task, sensors::sensors_task, wifi::wifi_task, Pms7003Data};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// It is necessary to call this function once. Otherwise some patches to the runtime
|
||||
@ -17,9 +25,8 @@ fn main() -> Result<()> {
|
||||
esp_idf_svc::sys::link_patches();
|
||||
|
||||
// Initialize NVS
|
||||
// esp_idf_hal::nvs::EspDefaultNvsPartition::take()
|
||||
// .context("Could not take NVS partition")?;
|
||||
esp_idf_svc::log::EspLogger::initialize_default();
|
||||
EspLogger::initialize_default();
|
||||
let nvs = EspDefaultNvsPartition::take()?;
|
||||
|
||||
let peripherals = Peripherals::take()?;
|
||||
let i2c = peripherals.i2c0;
|
||||
@ -32,7 +39,7 @@ fn main() -> Result<()> {
|
||||
let tx = peripherals.pins.gpio17;
|
||||
let rx = peripherals.pins.gpio16;
|
||||
|
||||
let config = config::Config::new().baudrate(Hertz(9600));
|
||||
let config = uart::config::Config::new().baudrate(Hertz(9600));
|
||||
let uart = UartDriver::new(
|
||||
peripherals.uart2,
|
||||
tx,
|
||||
@ -42,19 +49,28 @@ fn main() -> Result<()> {
|
||||
&config,
|
||||
)?;
|
||||
|
||||
let pm_data = Arc::new(Mutex::new(Pms7003Data::default()));
|
||||
let sysloop = EspSystemEventLoop::take()?;
|
||||
let modem = peripherals.modem;
|
||||
|
||||
let pm_data1 = Arc::clone(&pm_data);
|
||||
let pm_data2 = Arc::clone(&pm_data);
|
||||
let pm_data = Arc::new(Mutex::new(Pms7003Data::default()));
|
||||
let oled_arc = Arc::clone(&pm_data);
|
||||
let sensors_arc = Arc::clone(&pm_data);
|
||||
// let wifi_arc = Arc::clone(&pm_data);
|
||||
|
||||
let handles = vec![
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = oled_task(pm_data1, i2c) {
|
||||
if let Err(e) = oled_task(oled_arc, i2c) {
|
||||
log::error!("OLED Task Error: {:?}", e);
|
||||
}
|
||||
}),
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = pm_sensor_task(pm_data2, &uart) {
|
||||
if let Err(e) = sensors_task(sensors_arc, &uart) {
|
||||
log::error!("PM Sensor Task Error: {:?}", e);
|
||||
}
|
||||
}),
|
||||
thread::spawn(move || {
|
||||
// if let Err(e) = wifi_task(wifi_arc, &uart) {
|
||||
if let Err(e) = wifi_task(modem, sysloop, nvs) {
|
||||
log::error!("PM Sensor Task Error: {:?}", e);
|
||||
}
|
||||
}),
|
||||
|
@ -1,10 +1,13 @@
|
||||
use crate::Pms7003Data;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use log::{info, warn};
|
||||
use anyhow::Result;
|
||||
use log::{info, warn};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use esp_idf_svc::hal::{delay::{FreeRtos, BLOCK}, uart::UartDriver};
|
||||
use esp_idf_svc::hal::{
|
||||
delay::{FreeRtos, BLOCK},
|
||||
uart::UartDriver,
|
||||
};
|
||||
|
||||
// u16::from_be_bytes is too verbose
|
||||
fn get_u16(buf: &[u8]) -> u16 {
|
||||
@ -45,7 +48,7 @@ fn send_pms7003_command(uart: &UartDriver, cmd: u8, datah: u8, datal: u8) -> Res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pm_sensor_task(pm_data: Arc<Mutex<Pms7003Data>>, uart: &UartDriver) -> Result<()> {
|
||||
pub fn sensors_task(pm_data: Arc<Mutex<Pms7003Data>>, uart: &UartDriver) -> Result<()> {
|
||||
info!("Staring UART PM Sensor Task");
|
||||
|
||||
send_pms7003_command(uart, 0xE1, 0x00, 0x00)?;
|
||||
|
@ -1,79 +1,192 @@
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
use anyhow::bail;
|
||||
|
||||
use esp_idf_svc::{
|
||||
eventloop::EspSystemEventLoop,
|
||||
hal::peripheral,
|
||||
wifi::{AuthMethod, BlockingWifi, ClientConfiguration, Configuration, EspWifi},
|
||||
nvs::EspDefaultNvsPartition,
|
||||
sys::{
|
||||
esp, esp_err_t, wifi_prov_event_handler_t, wifi_prov_mgr_config_t, wifi_prov_mgr_deinit, wifi_prov_mgr_init, wifi_prov_mgr_is_provisioned, wifi_prov_mgr_start_provisioning, wifi_prov_mgr_stop_provisioning, wifi_prov_mgr_wait, wifi_prov_scheme_ble, wifi_prov_security_WIFI_PROV_SECURITY_1, wifi_prov_security_t, EspError
|
||||
},
|
||||
wifi::{BlockingWifi, ClientConfiguration, Configuration, EspWifi},
|
||||
};
|
||||
use std::ffi::c_void;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
pub fn wifi(
|
||||
ssid: &str,
|
||||
pass: &str,
|
||||
pub struct WifiProvisioning;
|
||||
|
||||
impl WifiProvisioning {
|
||||
pub fn new() -> Result<Self, EspError> {
|
||||
unsafe {
|
||||
// Updated struct initialization
|
||||
let config = wifi_prov_mgr_config_t {
|
||||
scheme: wifi_prov_scheme_ble, // ble provisioning
|
||||
scheme_event_handler: wifi_prov_event_handler_t {
|
||||
event_cb: None, // No custom callback
|
||||
user_data: ptr::null_mut(),
|
||||
},
|
||||
app_event_handler: wifi_prov_event_handler_t {
|
||||
event_cb: None, // No custom callback
|
||||
user_data: ptr::null_mut(),
|
||||
},
|
||||
};
|
||||
esp!(wifi_prov_mgr_init(config))?;
|
||||
}
|
||||
Ok(WifiProvisioning)
|
||||
}
|
||||
|
||||
pub fn start_provisioning(
|
||||
&self,
|
||||
security: wifi_prov_security_t,
|
||||
pop: &str,
|
||||
service_name: &str,
|
||||
service_key: Option<&str>,
|
||||
) -> Result<(), EspError> {
|
||||
let pop = CString::new(pop).unwrap();
|
||||
let service_name = CString::new(service_name).unwrap();
|
||||
let service_key = service_key.map(|key| CString::new(key).unwrap());
|
||||
let pop_ptr: *const c_void = pop.as_ptr() as *const c_void;
|
||||
unsafe {
|
||||
esp!(wifi_prov_mgr_start_provisioning(
|
||||
security,
|
||||
pop_ptr,
|
||||
service_name.as_ptr(),
|
||||
service_key.map_or(ptr::null(), |k| k.as_ptr()),
|
||||
))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wait(&self) {
|
||||
unsafe {
|
||||
wifi_prov_mgr_wait();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_provisioned(&self) -> Result<bool, EspError> {
|
||||
let mut provisioned: bool = false;
|
||||
let result: esp_err_t = unsafe { wifi_prov_mgr_is_provisioned(&mut provisioned) };
|
||||
if result == 0 {
|
||||
Ok(provisioned)
|
||||
} else {
|
||||
Err(EspError::from(result).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&self) {
|
||||
unsafe {
|
||||
wifi_prov_mgr_stop_provisioning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WifiProvisioning {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
wifi_prov_mgr_deinit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wifi_task(
|
||||
modem: impl peripheral::Peripheral<P = esp_idf_svc::hal::modem::Modem> + 'static,
|
||||
sysloop: EspSystemEventLoop,
|
||||
) -> anyhow::Result<Box<EspWifi<'static>>> {
|
||||
let mut auth_method = AuthMethod::WPA2Personal;
|
||||
if ssid.is_empty() {
|
||||
bail!("Missing WiFi name")
|
||||
}
|
||||
if pass.is_empty() {
|
||||
auth_method = AuthMethod::None;
|
||||
info!("Wifi password is empty");
|
||||
}
|
||||
let mut esp_wifi = EspWifi::new(modem, sysloop.clone(), None)?;
|
||||
nvs: EspDefaultNvsPartition,
|
||||
) -> Result<()> {
|
||||
info!("Provisioning device!");
|
||||
return Ok(());
|
||||
let wifi = EspWifi::new(modem, sysloop.clone(), Some(nvs))?;
|
||||
let mut wifi = BlockingWifi::wrap(wifi, sysloop)?;
|
||||
let prov = WifiProvisioning::new()?;
|
||||
if !prov.is_provisioned()? {
|
||||
let wifi_configuration: Configuration = Configuration::Client(ClientConfiguration {
|
||||
..Default::default()
|
||||
});
|
||||
wifi.set_configuration(&wifi_configuration)?;
|
||||
wifi.start()?;
|
||||
prov.start_provisioning(
|
||||
wifi_prov_security_WIFI_PROV_SECURITY_1,
|
||||
"abcd1234", // Proof of Possession (POP)
|
||||
"PROV_ESP32", // Service Name
|
||||
None, // No Service Key
|
||||
)?;
|
||||
|
||||
let mut wifi = BlockingWifi::wrap(&mut esp_wifi, sysloop)?;
|
||||
println!("Waiting for Wi-Fi provisioning...");
|
||||
prov.wait();
|
||||
|
||||
wifi.set_configuration(&Configuration::Client(ClientConfiguration::default()))?;
|
||||
|
||||
info!("Starting wifi...");
|
||||
|
||||
wifi.start()?;
|
||||
|
||||
info!("Scanning...");
|
||||
|
||||
let ap_infos = wifi.scan()?;
|
||||
|
||||
let ours = ap_infos.into_iter().find(|a| a.ssid == ssid);
|
||||
|
||||
let channel = if let Some(ours) = ours {
|
||||
info!(
|
||||
"Found configured access point {} on channel {}",
|
||||
ssid, ours.channel
|
||||
);
|
||||
Some(ours.channel)
|
||||
println!("Provisioning completed. Stopping...");
|
||||
prov.stop();
|
||||
} else {
|
||||
info!(
|
||||
"Configured access point {} not found during scanning, will go with unknown channel",
|
||||
ssid
|
||||
);
|
||||
None
|
||||
};
|
||||
|
||||
wifi.set_configuration(&Configuration::Client(ClientConfiguration {
|
||||
ssid: ssid
|
||||
.try_into()
|
||||
.expect("Could not parse the given SSID into WiFi config"),
|
||||
password: pass
|
||||
.try_into()
|
||||
.expect("Could not parse the given password into WiFi config"),
|
||||
channel,
|
||||
auth_method,
|
||||
..Default::default()
|
||||
}))?;
|
||||
|
||||
info!("Connecting wifi...");
|
||||
|
||||
wifi.connect()?;
|
||||
|
||||
info!("Waiting for DHCP lease...");
|
||||
|
||||
wifi.start()?;
|
||||
wifi.connect()?;
|
||||
}
|
||||
wifi.wait_netif_up()?;
|
||||
|
||||
let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
|
||||
println!("Wifi DHCP info: {:?}", ip_info);
|
||||
|
||||
info!("Wifi DHCP info: {:?}", ip_info);
|
||||
// let mut auth_method = AuthMethod::WPA2Personal;
|
||||
// if ssid.is_empty() {
|
||||
// bail!("Missing WiFi name")
|
||||
// }
|
||||
// if pass.is_empty() {
|
||||
// auth_method = AuthMethod::None;
|
||||
// info!("Wifi password is empty");
|
||||
// }
|
||||
// let mut esp_wifi = EspWifi::new(modem, sysloop.clone(), None)?;
|
||||
|
||||
Ok(Box::new(esp_wifi))
|
||||
// let mut wifi = BlockingWifi::wrap(&mut esp_wifi, sysloop)?;
|
||||
|
||||
// wifi.set_configuration(&Configuration::Client(ClientConfiguration::default()))?;
|
||||
|
||||
// info!("Starting wifi...");
|
||||
|
||||
// wifi.start()?;
|
||||
|
||||
// info!("Scanning...");
|
||||
|
||||
// let ap_infos = wifi.scan()?;
|
||||
|
||||
// let ours = ap_infos.into_iter().find(|a| a.ssid == ssid);
|
||||
|
||||
// let channel = if let Some(ours) = ours {
|
||||
// info!(
|
||||
// "Found configured access point {} on channel {}",
|
||||
// ssid, ours.channel
|
||||
// );
|
||||
// Some(ours.channel)
|
||||
// } else {
|
||||
// info!(
|
||||
// "Configured access point {} not found during scanning, will go with unknown channel",
|
||||
// ssid
|
||||
// );
|
||||
// None
|
||||
// };
|
||||
|
||||
// wifi.set_configuration(&Configuration::Client(ClientConfiguration {
|
||||
// ssid: ssid
|
||||
// .try_into()
|
||||
// .expect("Could not parse the given SSID into WiFi config"),
|
||||
// password: pass
|
||||
// .try_into()
|
||||
// .expect("Could not parse the given password into WiFi config"),
|
||||
// channel,
|
||||
// auth_method,
|
||||
// ..Default::default()
|
||||
// }))?;
|
||||
|
||||
// info!("Connecting wifi...");
|
||||
|
||||
// wifi.connect()?;
|
||||
|
||||
// info!("Waiting for DHCP lease...");
|
||||
|
||||
// wifi.wait_netif_up()?;
|
||||
|
||||
// let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
|
||||
|
||||
// info!("Wifi DHCP info: {:?}", ip_info);
|
||||
|
||||
// Ok(Box::new(esp_wifi))
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user