use std::thread;
use embedded_svc::{wifi::{Configuration, ClientConfiguration, AuthMethod}, utils::mqtt::client::ConnState, mqtt::client::{MessageImpl, QoS, Connection}};
use esp_idf_hal::prelude::Peripherals;
use esp_idf_svc::{eventloop::EspSystemEventLoop, nvs::EspDefaultNvsPartition, wifi::{EspWifi, BlockingWifi}, mqtt::client::{EspMqttClient, MqttClientConfiguration}};
use esp_idf_sys::{self as _, EspError}; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use log::*;
// Code closely follows what has been done here https://github.com/WoongH/esp32-rust-aws-iot-example/blob/main/src/main.rs
const WIFI_SSID: &str = "Wokwi-GUEST";
const WIFI_PASS: &str = "";
// The topics to which we subscribe.
const MQTT_ENDPOINT: &str = "mqtts://broker.emqx.io:8883"; // host:port
const MQTT_CLIENT_ID: &str = "esp32_epaper_test_publish";
const MQTT_TOPIC_NAME: &str = "esp32_epaper_test_publish_topic";
fn main() -> Result<(), EspError> {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_sys::link_patches();
// Bind the log crate to the ESP Logging facilities
esp_idf_svc::log::EspLogger::initialize_default();
let peripherals = Peripherals::take().unwrap();
let sys_loop = EspSystemEventLoop::take()?;
let nvs = EspDefaultNvsPartition::take()?;
// Blocking so that we can block until the IP is obtained
let mut wifi = BlockingWifi::wrap(
EspWifi::new(peripherals.modem, sys_loop.clone(), Some(nvs))?,
sys_loop,
)?;
configure_wifi(&mut wifi)?;
let _mqtt_client: EspMqttClient<ConnState<MessageImpl, EspError>> = test_mqtt_client()?;
loop {}
}
fn configure_wifi(wifi: &mut BlockingWifi<EspWifi>) -> Result<(), EspError> {
wifi.set_configuration(&Configuration::Client(ClientConfiguration {
ssid: WIFI_SSID.into(),
password: WIFI_PASS.into(),
auth_method: AuthMethod::None,
..Default::default()
}))?;
wifi.start()?;
info!("Wifi started!");
wifi.connect()?;
info!("Wifi connected!");
wifi.wait_netif_up()?;
info!("Wifi ready!");
Ok(())
}
fn test_mqtt_client() -> Result<EspMqttClient<ConnState<MessageImpl, EspError>>, EspError> {
info!("About to start MQTT client");
let conf = MqttClientConfiguration {
client_id: Some(MQTT_CLIENT_ID),
crt_bundle_attach: Some(esp_idf_sys::esp_crt_bundle_attach),
..Default::default()
};
let (mut client, mut connection) =
EspMqttClient::new_with_conn(MQTT_ENDPOINT, &conf)?;
info!("MQTT client started");
// Need to immediately start pumping the connection for messages, or else subscribe() and publish() below will not work
// Note that when using the alternative constructor - `EspMqttClient::new` - you don't need to
// spawn a new thread, as the messages will be pumped with a backpressure into the callback you provide.
// Yet, you still need to efficiently process each message in the callback without blocking for too long.
//
// Note also that if you go to http://tools.emqx.io/ and then connect and send a message to the specified topic,
// the client configured here should receive it.
thread::spawn(move || {
info!("MQTT Listening for messages");
while let Some(msg) = connection.next() {
match msg {
Err(e) => info!("MQTT Message ERROR: {}", e),
Ok(msg) => info!("MQTT Message: {:?}", msg),
}
}
info!("MQTT connection loop exit");
});
client.subscribe(MQTT_TOPIC_NAME, QoS::AtMostOnce)?;
info!("Subscribed to all topics ({})", MQTT_TOPIC_NAME);
client.publish(
MQTT_TOPIC_NAME,
QoS::AtMostOnce,
false,
format!("Hello from {}!", MQTT_TOPIC_NAME).as_bytes(),
)?;
info!("Published a hello message to topic \"{}\".", MQTT_TOPIC_NAME);
Ok(client)
}