use core::cell::RefCell; use core::ops::Add; use core::ops::Mul; use core::ops::Sub; use aht20_driver::AHT20; use alloc::rc::Rc; use core::default::Default; use embedded_hal_bus::i2c::RcDevice; //use ens160_aq::Ens160; use ens160::Ens160; use esp_hal::Blocking; use esp_hal::delay::Delay; use esp_hal::gpio::interconnect::PeripheralOutput; use esp_hal::i2c::master::I2c; use esp_hal::i2c::master::Instance; use esp_hal::time::Duration; use esp_hal::time::Instant; use heapless::HistoryBuf; pub struct Sampler<'a> { ens160: Ens160>>, aht20: aht20_driver::AHT20Initialized>>, } #[derive(Clone, Copy, Debug)] pub struct Sample { pub temperature: f32, pub humidity: f32, pub eco2: f32, pub tvoc: f32, } impl Sample { pub fn zero() -> Self { Sample { temperature: 0., humidity: 0., eco2: 0., tvoc: 0., } } } impl Add for Sample { type Output = Sample; fn add(self, rhs: Sample) -> Self::Output { Sample { temperature: self.temperature + rhs.temperature, humidity: self.humidity + rhs.humidity, eco2: self.eco2 + rhs.eco2, tvoc: self.tvoc + rhs.tvoc, } } } impl Sub for Sample { type Output = Sample; fn sub(self, rhs: Sample) -> Self::Output { Sample { temperature: self.temperature - rhs.temperature, humidity: self.humidity - rhs.humidity, eco2: self.eco2 - rhs.eco2, tvoc: self.tvoc - rhs.tvoc, } } } impl Mul for Sample { type Output = Sample; fn mul(self, rhs: Sample) -> Self::Output { Sample { temperature: self.temperature * rhs.temperature, humidity: self.humidity * rhs.humidity, eco2: self.eco2 * rhs.eco2, tvoc: self.tvoc * rhs.tvoc, } } } impl Mul for Sample { type Output = Sample; fn mul(self, rhs: f32) -> Self::Output { Sample { temperature: self.temperature * rhs, humidity: self.humidity * rhs, eco2: self.eco2 * rhs, tvoc: self.tvoc * rhs, } } } impl<'a> Sampler<'a> { pub fn new( i2c: impl Instance + 'a, sda: impl PeripheralOutput<'a>, scl: impl PeripheralOutput<'a>, timer: &mut Delay, ) -> Self { let i2c = I2c::new(i2c, Default::default()) .unwrap() .with_sda(sda) .with_scl(scl); let i2c = Rc::new(RefCell::new(i2c)); let mut ens160 = Ens160::new(embedded_hal_bus::i2c::RcDevice::new(i2c.clone()), 0x53); timer.delay_millis(500); ens160.reset().unwrap(); timer.delay_millis(500); ens160.operational().unwrap(); let aht20_uninit = AHT20::new( embedded_hal_bus::i2c::RcDevice::new(i2c.clone()), aht20_driver::SENSOR_ADDRESS, ); let aht20 = aht20_uninit.init(timer).unwrap(); Sampler { ens160, aht20 } } pub fn sample(&mut self, timer: &mut Delay) -> Sample { let aht20_measurement = self.aht20.measure(timer).unwrap(); Sample { temperature: aht20_measurement.temperature, humidity: aht20_measurement.humidity, eco2: *self.ens160.eco2().unwrap() as f32, tvoc: self.ens160.tvoc().unwrap() as f32, } } } pub const SECONDS_PER_SAMPLES: usize = 1; pub const MIN_5_LENGTH: usize = (5 * 60) / SECONDS_PER_SAMPLES; pub struct History { // 5 minutes, every 5 seconds pub min5: heapless::history_buf::HistoryBuf, // 2 hours every 5 seconds pub hour2: heapless::history_buf::HistoryBuf, // 24 hours every 5 minutes pub day: heapless::history_buf::HistoryBuf, samples_since_day: u32, last_sample: Instant, } impl History { pub fn new(sampler: &mut Sampler, timer: &mut Delay) -> Self { let mut min5 = HistoryBuf::new(); let mut hour2 = HistoryBuf::new(); let mut day = HistoryBuf::new(); // First sampler let sample = sampler.sample(timer); min5.write(sample); hour2.write(sample); day.write(sample); History { min5, hour2, day, samples_since_day: 0, last_sample: Instant::now(), } } pub fn update(&mut self, sampler: &mut Sampler, timer: &mut Delay) -> bool { let now = Instant::now(); if now - self.last_sample > Duration::from_secs(SECONDS_PER_SAMPLES as u64) { let sample = sampler.sample(timer); self.last_sample = Instant::now(); self.samples_since_day += 1; if self.samples_since_day as usize == MIN_5_LENGTH { // Compute average let avg = self.min5.iter().fold(Sample::zero(), |a, b| a + *b) * (1. / self.min5.len() as f32); self.day.write(avg); self.samples_since_day = 0; } self.min5.write(sample); self.hour2.write(sample); true } else { false } } }