// src/bin/main.rs #![no_std] #![no_main] #![deny( clippy::mem_forget, reason = "mem::forget is generally not safe to do with esp_hal types" )] use embassy_executor::Spawner; use embassy_futures::select::{select, Either}; use embassy_net::{Runner, StackResources}; use embassy_time::{Duration, Timer}; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; use esp_wifi::{ init, wifi::{ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState}, EspWifiController, }; use log::info; use rust_mqtt::packet::v5::publish_packet::QualityOfService; use projekt_final::mqtt::client::{ mqtt_events, mqtt_publish, mqtt_subscribe, mqtt_task, IncomingMsg, }; use defmt_rtt as _; extern crate alloc; esp_bootloader_esp_idf::esp_app_desc!(); macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); #[deny(unused_attributes)] let x = STATIC_CELL.uninit().write(($val)); x }}; } const SSID: &str = env!("SSID"); const PASSWORD: &str = env!("PASSWORD"); #[esp_hal_embassy::main] async fn main(spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals = esp_hal::init(config); esp_alloc::heap_allocator!(size: 72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); let mut rng = Rng::new(peripherals.RNG); let esp_wifi_ctrl = &*mk_static!( EspWifiController<'static>, init(timg0.timer0, rng.clone()).unwrap() ); let (controller, interfaces) = esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); let wifi_interface = interfaces.sta; let timg1 = TimerGroup::new(peripherals.TIMG1); esp_hal_embassy::init(timg1.timer0); let config = embassy_net::Config::dhcpv4(Default::default()); let seed = (rng.random() as u64) << 32 | rng.random() as u64; // Init network stack let (stack, runner) = embassy_net::new( wifi_interface, config, mk_static!(StackResources<3>, StackResources::<3>::new()), seed, ); spawner.spawn(connection(controller)).ok(); spawner.spawn(net_task(runner)).ok(); // Wait for link up loop { if stack.is_link_up() { break; } Timer::after(Duration::from_millis(500)).await; } info!("Waiting to get IP address..."); loop { if let Some(config) = stack.config_v4() { info!("Got IP: {}", config.address); break; } Timer::after(Duration::from_millis(500)).await; } spawner.spawn(mqtt_task(stack)).expect("failed to spawn MQTT task"); info!("MQTT task started"); mqtt_publish("esp32/topic", b"hello from ESP32 (init)", QualityOfService::QoS1, false).await; info!("Sent initial MQTT message"); mqtt_subscribe("esp32/topic").await; // Get a receiver for incoming MQTT messages let mqtt_rx = mqtt_events(); loop { // Drive both: either process an MQTT message or publish periodically match select(mqtt_rx.receive(), Timer::after(Duration::from_secs(5))).await { // Received inbound MQTT message (from broker) Either::First(msg) => { handle_incoming(msg); } // Time-based example publish Either::Second(_) => { // mqtt_publish( // "esp32/topic", // b"hello from main", // QualityOfService::QoS1, // false, // ) // .await; } } } } fn handle_incoming(msg: IncomingMsg) { if let Ok(txt) = core::str::from_utf8(&msg.payload) { info!("MAIN RX [{}]: {}", msg.topic.as_str(), txt); info!("Received MQTT message -> topic: '{}', payload: '{}'", msg.topic.as_str(), txt); } else { info!("MAIN RX [{}]: {:?}", msg.topic.as_str(), msg.payload); } } #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { info!("start connection task"); info!("Device capabilities: {:?}", controller.capabilities()); loop { match esp_wifi::wifi::wifi_state() { WifiState::StaConnected => { 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.into(), password: PASSWORD.into(), ..Default::default() }); controller.set_configuration(&client_config).unwrap(); info!("Starting wifi"); controller.start_async().await.unwrap(); info!("Wifi started!"); } info!("About to connect..."); match controller.connect_async().await { Ok(_) => info!("Wifi connected!"), Err(e) => { info!("Failed to connect to wifi: {e:?}"); Timer::after(Duration::from_millis(5000)).await } } } } #[embassy_executor::task] async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { runner.run().await }