#![no_std] #![no_main] #![feature(type_alias_impl_trait)] use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Config, Ipv4Address, Stack, StackResources}; use esp_hal::{self, IO}; use const_format::formatcp; use embassy_time::{Duration, Timer}; use embedded_hal_async::digital::Wait; use esp_backtrace as _; use esp_hal::clock::ClockControl; use esp_hal::gpio::{AnyPin, Input, PullUp}; use esp_hal::Rng; use esp_hal::{embassy, peripherals::Peripherals, prelude::*, timer::TimerGroup}; use esp_println::println; use esp_wifi::wifi::{ClientConfiguration, Configuration}; use esp_wifi::wifi::{WifiController, WifiDevice, WifiEvent, WifiStaDevice, WifiState}; use esp_wifi::{initialize, EspWifiInitFor}; use static_cell::make_static; const SSID: &str = env!("SSID"); const PASSWORD: &str = env!("PASSWORD"); #[main] async fn main(spawner: Spawner) { #[cfg(feature = "log")] esp_println::logger::init_logger(log::LevelFilter::Info); let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); let clocks = ClockControl::max(system.clock_control).freeze(); #[cfg(target_arch = "xtensa")] let timer = esp_hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0; #[cfg(target_arch = "riscv32")] let timer = esp_hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; let init = initialize( EspWifiInitFor::Wifi, timer, Rng::new(peripherals.RNG), system.radio_clock_control, &clocks, ) .unwrap(); let wifi = peripherals.WIFI; let (wifi_interface, controller) = esp_wifi::wifi::new_with_mode(&init, wifi, WifiStaDevice).unwrap(); let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); embassy::init(&clocks, timer_group0); let config = Config::dhcpv4(Default::default()); let seed = 1234; // very random, very secure seed // Init network stack let stack = &*make_static!(Stack::new( wifi_interface, config, make_static!(StackResources::<3>::new()), seed )); spawner.spawn(connection(controller)).ok(); spawner.spawn(net_task(&stack)).ok(); loop { if stack.is_link_up() { break; } Timer::after(Duration::from_millis(500)).await; } println!("Waiting to get IP address..."); loop { if let Some(config) = stack.config_v4() { println!("Got IP: {}", config.address); break; } Timer::after(Duration::from_millis(500)).await; } let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let button = io.pins.gpio12.into_pull_up_input(); println!("Spawning button task"); spawner.must_spawn(button_task(button.into(), stack)); } async fn ring(stack: &'static Stack>) -> Result<(), &str> { let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; Timer::after(Duration::from_millis(1_000)).await; let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); let remote_endpoint = (Ipv4Address::new(104, 20, 43, 236), 80); println!("connecting..."); let r = socket.connect(remote_endpoint).await; if let Err(e) = r { println!("connect error: {:?}", e); return Err("connect error"); } const JSON: &'static str = "{ \"token\": \"ahgvt9acdx5sowxfobadt9cmpqhrzp\", \"user\": \"ud2btptjwvy92xi8y77tfurfew6z7a\", \"message\": \"DOOR BELL!!!\" }"; const JSON_LEN: usize = JSON.len(); println!("connected!"); let mut buf = [0; 1024]; loop { use embedded_io_async::Write; let req = formatcp!("POST /1/messages.json HTTP/1.0\r\nHost: api.pushover.net\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}\r\n\r\n", JSON_LEN, JSON); println!("{}", req); let r = socket.write_all(req.as_bytes()).await; if let Err(e) = r { println!("write error: {:?}", e); break; } let n = match socket.read(&mut buf).await { Ok(0) => { println!("read EOF"); break; } Ok(n) => n, Err(e) => { println!("read error: {:?}", e); break; } }; println!("{}", core::str::from_utf8(&buf[..n]).unwrap()); } Timer::after(Duration::from_millis(5000)).await; Ok(()) } #[embassy_executor::task] async fn button_task( mut button: AnyPin>, stack: &'static Stack>, ) { loop { button.wait_for_falling_edge().await.unwrap(); Timer::after_millis(10).await; if button.is_low().unwrap() { println!("Button pressed"); ring(stack) .await .unwrap_or_else(|e| println!("ring error: {}", e)); } } } #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { println!("start connection task"); println!("Device capabilities: {:?}", controller.get_capabilities()); loop { match esp_wifi::wifi::get_wifi_state() { WifiState::StaConnected => { // wait until we're no longer connected controller.wait_for_event(WifiEvent::StaDisconnected).await; Timer::after(Duration::from_millis(5000)).await } _ => {} } if !matches!(controller.is_started(), Ok(true)) { let client_config = Configuration::Client(ClientConfiguration { ssid: SSID.try_into().unwrap(), password: PASSWORD.try_into().unwrap(), ..Default::default() }); controller.set_configuration(&client_config).unwrap(); println!("Starting wifi"); controller.start().await.unwrap(); println!("Wifi started!"); } println!("About to connect..."); match controller.connect().await { Ok(_) => println!("Wifi connected!"), Err(e) => { println!("Failed to connect to wifi: {e:?}"); Timer::after(Duration::from_millis(5000)).await } } } } #[embassy_executor::task] async fn net_task(stack: &'static Stack>) { stack.run().await }