From 6b56aae92f7a53747a8f3bf41cc0104db01a5cd8 Mon Sep 17 00:00:00 2001 From: Brendan Ball Date: Fri, 3 Nov 2023 09:33:15 +0100 Subject: [PATCH] abstract scd4x CO2 sensor --- Cargo.lock | 16 ++++++++--- Cargo.toml | 3 ++- esp32c3_nostd/Cargo.toml | 2 +- esp32c3_nostd/src/main.rs | 51 ++++------------------------------- sensor/Cargo.toml | 15 +++++++++++ sensor/src/lib.rs | 12 +++++++++ sensor/src/scd4x_sensor.rs | 55 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 52 deletions(-) create mode 100644 sensor/Cargo.toml create mode 100644 sensor/src/lib.rs create mode 100644 sensor/src/scd4x_sensor.rs diff --git a/Cargo.lock b/Cargo.lock index 3a524a4..0983a03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,7 +489,7 @@ dependencies = [ "log", "max7219", "max7219-driver", - "scd4x", + "sensor", ] [[package]] @@ -956,10 +956,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "scd4x" version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1e1abfa47df52b13ccc801bb4461849c718fee09cd4c8505012e2b565a2c36" dependencies = [ - "embedded-hal 0.2.7", + "embedded-hal 1.0.0-rc.1", + "log", "sensirion-i2c", ] @@ -1013,6 +1012,15 @@ dependencies = [ "embedded-hal 0.2.7", ] +[[package]] +name = "sensor" +version = "0.1.0" +dependencies = [ + "airquamon_domain", + "embedded-hal 1.0.0-rc.1", + "scd4x", +] + [[package]] name = "serde" version = "1.0.189" diff --git a/Cargo.toml b/Cargo.toml index 4119b2a..8a348f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,8 @@ members = [ "airquamon_domain", "display_themes", "esp32c3_nostd", - "epd_display" + "epd_display", + "sensor" ] resolver = "2" diff --git a/esp32c3_nostd/Cargo.toml b/esp32c3_nostd/Cargo.toml index 11def48..ea71e72 100644 --- a/esp32c3_nostd/Cargo.toml +++ b/esp32c3_nostd/Cargo.toml @@ -9,12 +9,12 @@ edition = "2021" airquamon_domain = { path = "../airquamon_domain" } display_themes = { path = "../display_themes" } epd_display = { path = "../epd_display" } +sensor = { path = "../sensor" } esp32c3-hal = { git = "https://github.com/esp-rs/esp-hal.git", rev = "33bfe80d958911f4d0b43adb89cca34b5dce1676", features = ["eh1"] } esp-hal-common = { git = "https://github.com/esp-rs/esp-hal.git", rev = "33bfe80d958911f4d0b43adb89cca34b5dce1676", features = ["esp32c3", "eh1"] } esp-backtrace = { version = "0.8.0", features = ["esp32c3", "panic-handler", "exception-handler", "print-uart"] } esp-println = { version = "0.6.0", features = ["esp32c3","log"] } log = { version = "0.4.18" } -scd4x = "0.2.1" epd-waveshare = { path = "/home/brendan/dev/projects/epd-waveshare" } embedded-graphics = "0.8.1" embedded-hal = "1.0.0-rc.1" diff --git a/esp32c3_nostd/src/main.rs b/esp32c3_nostd/src/main.rs index bc5aa29..991936a 100644 --- a/esp32c3_nostd/src/main.rs +++ b/esp32c3_nostd/src/main.rs @@ -14,13 +14,11 @@ use esp32c3_hal::{ prelude::*, Delay, }; -use embedded_hal::delay::DelayUs; -use scd4x::scd4x::Scd4x; use epd_waveshare::{epd2in9b_v3::{Display2in9b, Epd2in9b}, graphics::DisplayRotation}; use log::info; -use airquamon_domain::Data; use display_themes::Theme2; use epd_display::{Display, DisplayTheme}; +use sensor::{Sensor, Scd4xSensor}; #[entry] fn main() -> ! { @@ -49,7 +47,7 @@ fn main() -> ! { ); info!("Connecting to sensor"); - let mut sensor = Scd4x::new(i2c, delay); + let mut sensor = Scd4xSensor::new(i2c, delay); let mosi = io.pins.gpio4; let sck = io.pins.gpio5; @@ -90,57 +88,18 @@ fn main() -> ! { Theme2::new() ); - sensor.wake_up(); - // sensor.set_automatic_self_calibration(true).expect("failed enabling sensor automatic self calibration"); - sensor.stop_periodic_measurement().unwrap(); - sensor.reinit().unwrap(); - - let serial = sensor.serial_number().unwrap(); - info!("Serial: {:#04x}", serial); - loop { - // sensor.wake_up(); - info!("Starting periodic measurement"); - sensor.start_periodic_measurement().unwrap(); - DelayUs::delay_ms(&mut delay, 5000); - - info!("Waiting for data ready"); - loop { - match sensor.data_ready_status() { - Ok(true) => break, - Ok(false) => DelayUs::delay_ms(&mut delay, 100), - Err(e) => { - panic!("Failed to poll for data ready: {:?}", e); - }, - } - } - - info!("Reading sensor data"); - let data = match sensor.measurement() { - Ok(v) => v, - Err(e) => { - panic!("Failed to read measurement: {:?}", e); - }, - }; + let data = sensor.measure().expect("failed reading sensor"); info!( "CO2: {0}, Temperature: {1:#.2} °C, Humidity: {2:#.2} RH", data.co2, data.temperature, data.humidity ); - info!("Stop sensor periodic measurement"); - // sensor.power_down().expect("failed powering down sensor"); - sensor.stop_periodic_measurement().expect("failed to stop sensor periodic measurement"); - - info!("updating display"); - display.draw(&Data { - co2: data.co2, - temperature: data.temperature, - humidity: data.humidity, - }).expect("draw failed"); + display.draw(&data).expect("draw failed"); info!("Sleeping"); - DelayUs::delay_ms(&mut delay, 60000); + delay.delay_ms(60000u32); } } diff --git a/sensor/Cargo.toml b/sensor/Cargo.toml new file mode 100644 index 0000000..90cde87 --- /dev/null +++ b/sensor/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sensor" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +airquamon_domain = { path = "../airquamon_domain" } +embedded-hal = "1.0.0-rc.1" + +[dependencies.scd4x] +version = "0.2.1" +path = "../../../scd4x-rs" +default-features = false \ No newline at end of file diff --git a/sensor/src/lib.rs b/sensor/src/lib.rs new file mode 100644 index 0000000..094d36f --- /dev/null +++ b/sensor/src/lib.rs @@ -0,0 +1,12 @@ +#![no_std] + +use airquamon_domain::Data; + +mod scd4x_sensor; +pub use scd4x_sensor::Scd4xSensor; + +pub trait Sensor { + type Error; + + fn measure(&mut self) -> Result; +} \ No newline at end of file diff --git a/sensor/src/scd4x_sensor.rs b/sensor/src/scd4x_sensor.rs new file mode 100644 index 0000000..e1361b0 --- /dev/null +++ b/sensor/src/scd4x_sensor.rs @@ -0,0 +1,55 @@ +use airquamon_domain::Data; +use embedded_hal::{i2c::I2c, delay::DelayUs}; +use scd4x::{Scd4x, Error}; +use crate::Sensor; + +pub struct Scd4xSensor { + scd4x: Scd4x, + delay: DELAY, +} + +impl Scd4xSensor +where +I2C: I2c, +DELAY: DelayUs + Copy, +{ + pub fn new(i2c: I2C, delay: DELAY) -> Self { + Self { + scd4x: Scd4x::new(i2c, delay), + delay, + } + } +} + +impl Sensor for Scd4xSensor +where +I2C: I2c, +DELAY: DelayUs, +{ + + type Error = Error; + + fn measure(&mut self) -> Result { + self.scd4x.wake_up(); + self.scd4x.reinit()?; + self.scd4x.start_periodic_measurement()?; + self.delay.delay_ms(5000); + loop { + match self.scd4x.data_ready_status() { + Ok(true) => break, + Ok(false) => { + self.delay.delay_ms(100); + Ok(()) + }, + Err(e) => Err(e), + }?; + } + let data = self.scd4x.measurement()?; + self.scd4x.stop_periodic_measurement()?; + Ok(Data { + co2: data.co2, + temperature: data.temperature, + humidity: data.humidity + }) + } +} \ No newline at end of file