diff --git a/Cargo.toml b/Cargo.toml index c5179f9..b02a7ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ esp-idf-hal = "0.38.0" esp-idf-svc = "0.42.1" esp-idf-sys = { version = "0.31.6", features = ["binstart"] } log = "0.4.17" +serde = {version="1.0.144", features = ["derive"]} +serde_json = "1.0.83" [build-dependencies] diff --git a/src/blink.rs b/src/blink.rs index e54e65e..638dafd 100644 --- a/src/blink.rs +++ b/src/blink.rs @@ -38,10 +38,10 @@ where break; } self.toggle().unwrap(); - thread::sleep(Duration::from_millis(30)); + thread::sleep(Duration::from_millis(10)); self.toggle().unwrap(); - thread::sleep(Duration::from_millis(1930)); + thread::sleep(Duration::from_millis(990)); } } } diff --git a/src/eventloop.rs b/src/eventloop.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index 126e62a..082a88d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ -use embedded_svc::mqtt::client::{Publish, QoS}; -use esp_idf_sys as _; +use embedded_svc::event_bus::EventBus; +use esp_idf_svc::eventloop::{Background, EspBackgroundEventLoop, EspEventLoop}; +use esp_idf_sys::{self as _, EspError}; use log::*; use std::{ env, @@ -10,13 +11,16 @@ use std::{ mod blink; mod message_queue; mod time; -mod wifi; mod voltage_detection; +mod wifi; +use crate::voltage_detection::VoltageDetectionWorker; use crate::{ - message_queue::MessageQueue, time::Time, wifi::Internet, voltage_detection::VoltageDetection, + message_queue::MessageQueue, time::Time, voltage_detection::VoltageDetection, wifi::Internet, }; +static mut EVENTLOOP: Option>> = None; + fn main() { env::set_var("DEFMT_LOG", "trace"); env::set_var("RUST_BACKTRACE", "1"); @@ -40,6 +44,12 @@ fn main() { let sda_pin = peripherals.pins.gpio4; let scl_pin = peripherals.pins.gpio10; + info!("About to start a background event loop"); + match EspBackgroundEventLoop::new(&Default::default()) { + Ok(eventloop) => unsafe { EVENTLOOP = Some(eventloop) }, + Err(err) => error!("Init Event Loop failed. {:?}", err), + }; + thread::spawn(move || { let mut blink = blink::Blink::new( blink_pin @@ -51,7 +61,9 @@ fn main() { let mut voltage_detection = VoltageDetection::new(); - voltage_detection.watching().expect("Can not watch voltages."); + voltage_detection + .watching() + .expect("Can not watch voltages."); let _wifi = Internet::new().unwrap(); @@ -61,21 +73,35 @@ fn main() { let mut time = Time::new(); time.sync().unwrap(); + let _subscription; + if let Some(eventloop) = unsafe { EVENTLOOP.as_mut() } { + _subscription = eventloop + .subscribe(move |message: &VoltageDetectionWorker| { + info!("Event Loop Value"); + if let Ok(json_str) = serde_json::to_string(&message) { + if let Err(err) = mq.publish("voltage", json_str.as_bytes()) { + warn!("Can not publish message to MQTT. {}", err); + } + } + }) + .expect(" Listening Event Loop Failed"); + } + loop { sleep(Duration::from_millis(1000)); - if let Some(ref mut mq_client) = mq.client { - let timestamps = time.get_time().as_millis(); + // if let Some(ref mut mq_client) = mq.client { + // let timestamps = time.get_time().as_millis(); - info!("timestamps {}", timestamps); - mq_client - .publish( - "ups-0.2/heartbeat", - QoS::AtMostOnce, - false, - timestamps.to_string().as_bytes(), - ) - .map_err(|err| warn!("publish heartbeat failed {}", err)) - .unwrap(); - } + // info!("timestamps {}", timestamps); + // mq_client + // .publish( + // "ups-0.2/heartbeat", + // QoS::AtMostOnce, + // false, + // timestamps.to_string().as_bytes(), + // ) + // .map_err(|err| warn!("publish heartbeat failed {}", err)) + // .unwrap(); + // } } } diff --git a/src/message_queue.rs b/src/message_queue.rs index 59b4056..905eaac 100644 --- a/src/message_queue.rs +++ b/src/message_queue.rs @@ -61,13 +61,16 @@ impl MessageQueue { anyhow::Ok(()) } - pub fn publish(&mut self, bytes: &[u8]) -> Result { + pub fn publish(&mut self, topic: &str, bytes: &[u8]) -> Result { self.client - .as_mut() + .as_mut() .unwrap() - .publish("", QoS::AtMostOnce, false, bytes) - .map_err(|err| { - anyhow::anyhow!("publish message to queue was failed!. {}", err) - }) + .publish( + format!("{}/{}", "ups_0_2", topic).as_str(), + QoS::AtMostOnce, + false, + bytes, + ) + .map_err(|err| anyhow::anyhow!("publish message to queue was failed!. {}", err)) } } diff --git a/src/voltage_detection.rs b/src/voltage_detection.rs index 77213d1..c37fd78 100644 --- a/src/voltage_detection.rs +++ b/src/voltage_detection.rs @@ -3,24 +3,41 @@ use std::{ time::Duration, }; -use embedded_hal::{adc::Channel, prelude::_embedded_hal_adc_OneShot, digital::v2::OutputPin}; -use embedded_svc::timer::{PeriodicTimer, TimerService}; +use embedded_hal::{adc::Channel, prelude::_embedded_hal_adc_OneShot}; +use embedded_svc::{ + event_bus::Postbox, + timer::{PeriodicTimer, TimerService}, +}; use esp_idf_hal::{ adc::{ config::{self}, Analog, PoweredAdc, ADC1, }, - gpio::{Gpio1, Gpio2, Gpio3, Input, Pull}, + gpio::{Gpio1, Gpio2, Gpio3, Input}, }; -use esp_idf_svc::timer::{EspTimer, EspTimerService}; +use esp_idf_svc::{ + eventloop::{ + EspEventFetchData, EspEventPostData, EspTypedEventDeserializer, EspTypedEventSerializer, + EspTypedEventSource, + }, + timer::{EspTimer, EspTimerService}, +}; +use esp_idf_sys::c_types; use log::{info, warn}; +use serde::{Deserialize, Serialize}; + +use crate::EVENTLOOP; + +const ADAPTER_OFFSET: f32 = 12002f32 / 900f32; +const BATTERY_OFFSET: f32 = 12002f32 / 900f32; +const OUTPUT_OFFSET: f32 = 12002f32 / 900f32; pub struct VoltageDetection { pub worker: VoltageDetectionWorker, watch_timer: Option, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Serialize, Deserialize)] pub struct VoltageDetectionWorker { pub adapter_voltage: u16, pub battery_voltage: u16, @@ -39,7 +56,7 @@ impl VoltageDetection { let worker = Arc::new(Mutex::new(self.worker)); let mut timer = EspTimerService::new()?.timer(move || { info!("One-shot timer triggered"); - match worker.as_ref().lock().as_mut() { + match worker.lock().as_mut() { Ok(worker) => { if let Err(err) = worker.read_once() { warn!("Read Failed. {}", err); @@ -48,6 +65,22 @@ impl VoltageDetection { "Adapter: {},\tBattery: {},\t Output: {}", worker.adapter_voltage, worker.battery_voltage, worker.output_voltage ); + if let Some(eventloop) = unsafe { EVENTLOOP.as_mut() } { + if let Err(err) = eventloop.post( + &mut VoltageDetectionWorker { + adapter_voltage: worker.adapter_voltage, + battery_voltage: worker.battery_voltage, + output_voltage: worker.output_voltage, + }, + None, + ) { + warn!("Post Result to Event Loop failed. {}", err); + } else { + info!("Event Loop Post"); + } + } else { + warn!("EVENTLOOP IS NONE"); + } } Err(err) => { warn!("Lock VoltageDetection Worker Failed. {}", err) @@ -60,6 +93,7 @@ impl VoltageDetection { return anyhow::Ok(()); } } + impl VoltageDetectionWorker { pub fn new() -> Self { return Self { @@ -71,11 +105,11 @@ impl VoltageDetectionWorker { pub fn read_once(&mut self) -> anyhow::Result<()> { let adapter_pin = unsafe { Gpio1::::new() } - .into_analog_atten_11db() + .into_analog_atten_6db() .map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?; match self.read_pin_once(adapter_pin) { Ok(voltage) => { - self.adapter_voltage = voltage; + self.adapter_voltage = ((voltage as f32) * ADAPTER_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); @@ -83,11 +117,11 @@ impl VoltageDetectionWorker { } let battery_pin = unsafe { Gpio2::::new() } - .into_analog_atten_11db() - .map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?; + .into_analog_atten_6db() + .map_err(|err| anyhow::anyhow!("Failed to set GPIO 2 as analog input. {}", err))?; match self.read_pin_once(battery_pin) { Ok(voltage) => { - self.battery_voltage = voltage; + self.battery_voltage = ((voltage as f32) * BATTERY_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); @@ -95,11 +129,11 @@ impl VoltageDetectionWorker { } let output_pin = unsafe { Gpio3::::new() } - .into_analog_atten_11db() - .map_err(|err| anyhow::anyhow!("Failed to set GPIO 1 as analog input. {}", err))?; + .into_analog_atten_6db() + .map_err(|err| anyhow::anyhow!("Failed to set GPIO 3 as analog input. {}", err))?; match self.read_pin_once(output_pin) { Ok(voltage) => { - self.output_voltage = voltage; + self.output_voltage = ((voltage as f32) * OUTPUT_OFFSET) as u16; } Err(err) => { warn!("Adapter Voltage read failed: {:?}", err); @@ -115,10 +149,34 @@ impl VoltageDetectionWorker { let mut adc = PoweredAdc::new(unsafe { ADC1::new() }, config::Config::new())?; let voltage = adc.read(&mut pin); match voltage { - Ok(voltage) => anyhow::Ok((self.adapter_voltage + voltage * 10) / 11), + Ok(voltage) => anyhow::Ok(voltage), Err(err) => { anyhow::bail!("Adapter Voltage read failed: {:?}", err) } } } } + +impl EspTypedEventSource for VoltageDetectionWorker { + fn source() -> *const c_types::c_char { + b"VOLTAGES\0".as_ptr() as *const _ + } +} + +impl EspTypedEventSerializer for VoltageDetectionWorker { + fn serialize( + event: &VoltageDetectionWorker, + f: impl for<'a> FnOnce(&'a EspEventPostData) -> R, + ) -> R { + f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) }) + } +} + +impl EspTypedEventDeserializer for VoltageDetectionWorker { + fn deserialize( + data: &EspEventFetchData, + f: &mut impl for<'a> FnMut(&'a VoltageDetectionWorker) -> R, + ) -> R { + f(unsafe { data.as_payload() }) + } +}