diff --git a/.gitignore b/.gitignore index 73a638b..a882233 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /.embuild /target /Cargo.lock +.env diff --git a/Cargo.toml b/Cargo.toml index 803f3cf..621265b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,10 +30,13 @@ embassy = [ ] [dependencies] -anyhow = "1.0.79" +anyhow = "1" axum = { version = "0.7", features = ["http1", "json"] } esp-idf-sys = { version = "0.34", features = ["binstart"] } esp-idf-svc = { version = "0.48", default-features = false } +embedded-svc = { version = "0.27", features = ["experimental"] } +embedded-hal = "1.0" + futures = "0.3" log = { version = "0.4", default-features = false } mio = { version = "0.8", features = ["log"] } @@ -42,6 +45,8 @@ tokio = { version = "1", features = ["rt", "net", "io-util"] } tower-http = { version = "0" } [build-dependencies] +anyhow = "1" +dotenv = "0.15.0" embuild = "0.31.3" [dev-dependencies] diff --git a/README.md b/README.md index 8cb699f..27d03e6 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,10 @@ If you get an error like: Try to press the boot button on the ESP32 board and run the command again. +## Setup + +Copy `example.env` to `.env` and adjust the settings. + ## Building ```bash @@ -58,3 +62,12 @@ cargo build ```bash cargo espflash monitor ``` + +## License + +[MIT](LICENSE) + +## See also + +- [Tokio running on esp32!](https://github.com/jasta/esp32-tokio-demo) +- [IRC bot with JSON API for esp32](https://github.com/sjm42/esp32ircbot) diff --git a/build.rs b/build.rs index 112ec3f..08790e0 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,18 @@ -fn main() { +use std::env; + +fn main() -> anyhow::Result<()> { + dotenv::dotenv().ok(); embuild::espidf::sysenv::output(); + + let wifi_ssid = env::var("WIFI_SSID").unwrap_or_else(|_| "internet".into()); + let wifi_pass = env::var("WIFI_PASS").unwrap_or_else(|_| "password".into()); + let server_port = env::var("SERVER_PORT").unwrap_or_else(|_| "8080".into()); + + println!("cargo:rustc-env=WIFI_SSID={wifi_ssid}"); + println!("cargo:rustc-env=WIFI_PASS={wifi_pass}"); + println!("cargo:rustc-env=SERVER_PORT={server_port}"); + + Ok(()) } + +// EOF diff --git a/example.env b/example.env new file mode 100644 index 0000000..c12d804 --- /dev/null +++ b/example.env @@ -0,0 +1,3 @@ +WIFI_SSID=WIFI +WIFI_PASSWORD=PASSWORD +SERVER_PORT=8080 \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 74f47ad..4bf2a45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ pub mod server; +pub mod wifi; diff --git a/src/main.rs b/src/main.rs index 7a4cbc4..8473fc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,14 @@ -use esp32_rust_example::*; +use esp32_rust_example::{wifi::Wifi, *}; +use esp_idf_svc::hal::task::block_on; use anyhow::Ok; use esp_idf_sys::esp_app_desc; +use log::info; esp_app_desc!(); +const WIFI_SSID: &str = env!("WIFI_SSID"); + fn main() -> anyhow::Result<()> { esp_idf_svc::sys::link_patches(); @@ -12,5 +16,32 @@ fn main() -> anyhow::Result<()> { log::info!("Hello, world!"); + log::info!("WIFI_SSID: {}", WIFI_SSID); + + log::info!("Starting server..."); + + let mut wifi = Wifi::new()?; + + block_on(run(&mut wifi))?; + + info!("Shutting down in 5s..."); + + std::thread::sleep(core::time::Duration::from_secs(5)); + + Ok(()) +} + +async fn run(wifi: &mut Wifi<'static>) -> anyhow::Result<()> { + wifi.configure().await?; + wifi.connect().await?; + + server::server().await?; + + /* loop { + tokio::time::sleep(tokio::time::Duration::from_millis(1)).await; + } + + wifi.disconnect().await?; + */ Ok(()) } diff --git a/src/server.rs b/src/server.rs index c9e4f44..a609228 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,7 +2,7 @@ use axum::{response::Html, routing::get, Router}; use log::info; use tokio::net::TcpListener; -const TCP_LISTENING_PORT: u16 = 80; +const TCP_LISTENING_PORT: &str = env!("SERVER_PORT"); pub async fn server() -> anyhow::Result<()> { let addr = format!("0.0.0.0:{TCP_LISTENING_PORT}"); diff --git a/src/wifi.rs b/src/wifi.rs new file mode 100644 index 0000000..6d9a542 --- /dev/null +++ b/src/wifi.rs @@ -0,0 +1,64 @@ +use embedded_svc::wifi::{AuthMethod, ClientConfiguration, Configuration}; +use esp_idf_svc::eventloop::EspSystemEventLoop; +use esp_idf_svc::hal::peripherals::Peripherals; +use esp_idf_svc::nvs::EspDefaultNvsPartition; +use esp_idf_svc::timer::EspTaskTimerService; +use esp_idf_svc::wifi::{AsyncWifi, EspWifi}; +use esp_idf_sys as _; +use esp_idf_sys::EspError; +use log::info; + +const WIFI_SSID: &str = env!("WIFI_SSID"); +const WIFI_PASS: &str = env!("WIFI_PASS"); + +pub struct Wifi<'a> { + wifi: AsyncWifi>, +} + +impl<'a> Wifi<'a> { + pub fn new() -> anyhow::Result { + let peripherals = Peripherals::take()?; + let sys_loop = EspSystemEventLoop::take()?; + let timer_service = EspTaskTimerService::new()?; + let nvs = EspDefaultNvsPartition::take()?; + + let wifi = AsyncWifi::wrap( + EspWifi::new(peripherals.modem, sys_loop.clone(), Some(nvs))?, + sys_loop, + timer_service, + )?; + Ok(Self { wifi }) + } + + pub async fn configure(&mut self) -> Result<(), EspError> { + info!("Setting Wi-Fi credentials..."); + + let wifi_configuration: Configuration = Configuration::Client(ClientConfiguration { + ssid: WIFI_SSID.try_into().unwrap(), + bssid: None, + auth_method: AuthMethod::WPAWPA2Personal, + password: WIFI_PASS.try_into().unwrap(), + channel: None, + }); + + self.wifi.set_configuration(&wifi_configuration)?; + + info!("Starting Wi-Fi driver..."); + self.wifi.start().await + } + + pub async fn connect(&mut self) -> Result<(), EspError> { + self.wifi.connect().await?; + info!("Wifi connected"); + + self.wifi.wait_netif_up().await?; + info!("Wifi netif up"); + Ok(()) + } + + pub async fn disconnect(&mut self) -> Result<(), EspError> { + self.wifi.disconnect().await?; + info!("Wifi disconnected"); + Ok(()) + } +}