Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 0 additions & 130 deletions src/espressif.rs
Original file line number Diff line number Diff line change
@@ -1,130 +0,0 @@
use micro_rdk::{
common::{
config::ConfigType,
registry::{ComponentRegistry, Dependency, RegistryError},
sensor::{
GenericReadingsResult, Readings, Sensor, SensorError, SensorResult, SensorT,
SensorType, TypedReadingsResult,
},
status::{Status, StatusError},
},
esp32::esp_idf_svc::hal::sys::esp,
DoCommand,
};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

// idf component re-exported from esp-idf-svc build system
use micro_rdk::esp32::esp_idf_svc::sys::bme280::*;

/// Global handle to I2C bus
static mut I2C_BUS: i2c_bus_handle_t = std::ptr::null_mut();
/// Global handle to BME280 device
static mut BME280: bme280_handle_t = std::ptr::null_mut();
const I2C_MODE_MASTER: u32 = 0x1;

pub fn register_models(registry: &mut ComponentRegistry) -> Result<(), RegistryError> {
registry.register_sensor("bme280", &Bme280::from_config)
}

#[derive(DoCommand)]
pub struct Bme280 {}

impl Status for Bme280 {
fn get_status(&self) -> Result<Option<micro_rdk::google::protobuf::Struct>, StatusError> {
let fields = HashMap::new();
Ok(Some(micro_rdk::google::protobuf::Struct { fields }))
}
}

impl Sensor for Bme280 {}

impl Readings for Bme280 {
fn get_generic_readings(&mut self) -> Result<GenericReadingsResult, SensorError> {
Ok(self
.get_readings()?
.into_iter()
.map(|v| (v.0, SensorResult::<f64> { value: v.1 }.into()))
.collect())
}
}

impl SensorT<f64> for Bme280 {
fn get_readings(&self) -> Result<TypedReadingsResult<f64>, SensorError> {
let mut temperature: f32 = 0.0;
let mut pressure: f32 = 0.0;
let mut humidity: f32 = 0.0;
unsafe {
log::debug!("bme280 - reading temperature...");
esp!(bme280_read_temperature(
BME280,
&mut temperature as &mut f32
))?;
log::debug!("bme280 - reading pressure...");
esp!(bme280_read_pressure(BME280, &mut pressure as &mut f32))?;
log::debug!("bme280 - reading humidity...");
esp!(bme280_read_humidity(BME280, &mut humidity as &mut f32))?;
}
log::debug!(
"temperature: {}, humidity: {}, pressure: {}",
temperature,
humidity,
pressure
);
let mut x: HashMap<String, f64> = HashMap::new();
x.insert("temperature_c".to_string(), temperature.into());
x.insert("humidity".to_string(), humidity.into());
x.insert("pressure_hpa".to_string(), pressure.into());
Ok(x)
}
}

impl Bme280 {
pub fn from_config(cfg: ConfigType, _deps: Vec<Dependency>) -> Result<SensorType, SensorError> {
// DO NOT use the board i2c interface to initialize the i2c bus, the idf-component will handle it
let bus_no = cfg
.get_attribute::<i32>("i2c_bus")
.inspect_err(|_| {
log::warn!("`i2c_bus` attribute not found or invalid, defaulting to bus 0")
})
.unwrap_or_default();

let sda_pin = cfg
.get_attribute::<i32>("sda_pin")
.inspect_err(|_| {
log::info!("`sda_pin` attribute not found or invalid, defaulting to pin 22")
})
.unwrap_or(22);
let scl_pin = cfg
.get_attribute::<i32>("scl_pin")
.inspect_err(|_| {
log::info!("`scl_pin` attribute not found or invalid, defaulting to pin 21")
})
.unwrap_or(21);

let config = i2c_config_t {
mode: I2C_MODE_MASTER,
sda_io_num: sda_pin,
sda_pullup_en: true,
scl_io_num: scl_pin,
scl_pullup_en: true,
__bindgen_anon_1: i2c_config_t__bindgen_ty_1 {
master: i2c_config_t__bindgen_ty_1__bindgen_ty_1 { clk_speed: 100000 },
},
clk_flags: 0,
};

unsafe {
log::info!("initializing I2C_BUS: {:?}", I2C_BUS);
I2C_BUS = i2c_bus_create(bus_no, &config);
log::info!("initialized I2C_BUS to : {:?}", I2C_BUS);
log::info!("initializing BME280: {:?}", BME280);
BME280 = bme280_create(I2C_BUS, BME280_I2C_ADDRESS_DEFAULT.try_into().unwrap());
log::info!("initialized BME280 to : {:?}", BME280);
esp!(bme280_default_init(BME280))?;
}
Ok(Arc::new(Mutex::new(Self {})))
}
}
133 changes: 130 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,130 @@
//pub mod viam;
mod espressif;
pub use espressif::*;
use micro_rdk::{
common::{
config::ConfigType,
registry::{ComponentRegistry, Dependency, RegistryError},
sensor::{
GenericReadingsResult, Readings, Sensor, SensorError, SensorResult, SensorT,
SensorType, TypedReadingsResult,
},
status::{Status, StatusError},
},
esp32::esp_idf_svc::hal::sys::esp,
DoCommand,
};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

// idf component re-exported from esp-idf-svc build system
use micro_rdk::esp32::esp_idf_svc::sys::bme280::*;

/// Global handle to I2C bus
static mut I2C_BUS: i2c_bus_handle_t = std::ptr::null_mut();
/// Global handle to BME280 device
static mut BME280: bme280_handle_t = std::ptr::null_mut();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these cause compilation warnings about static mut references (to be deprecated). I'm not sure what I should use instead. Looking online there's references to a const_mut compiler feature, but it isn't stable just yet.

const I2C_MODE_MASTER: u32 = 0x1;

pub fn register_models(registry: &mut ComponentRegistry) -> Result<(), RegistryError> {
registry.register_sensor("bme280", &Bme280::from_config)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed, see if you can make this a triplet. not a blocker for merging.

@gvaradarajan Gautham Varadarajan (gvaradarajan) Mar 24, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not possible without an adjustment to registration logic in micro-RDK, see here: https://viam.atlassian.net/browse/RSDK-7822

}

#[derive(DoCommand)]
pub struct Bme280 {}

impl Status for Bme280 {
fn get_status(&self) -> Result<Option<micro_rdk::google::protobuf::Struct>, StatusError> {
let fields = HashMap::new();
Ok(Some(micro_rdk::google::protobuf::Struct { fields }))
}
}

impl Sensor for Bme280 {}

impl Readings for Bme280 {
fn get_generic_readings(&mut self) -> Result<GenericReadingsResult, SensorError> {
Ok(self
.get_readings()?
.into_iter()
.map(|v| (v.0, SensorResult::<f64> { value: v.1 }.into()))
.collect())
}
}

impl SensorT<f64> for Bme280 {
fn get_readings(&self) -> Result<TypedReadingsResult<f64>, SensorError> {
let mut temperature: f32 = 0.0;
let mut pressure: f32 = 0.0;
let mut humidity: f32 = 0.0;
unsafe {
log::debug!("bme280 - reading temperature...");
esp!(bme280_read_temperature(
BME280,
&mut temperature as &mut f32
))?;
log::debug!("bme280 - reading pressure...");
esp!(bme280_read_pressure(BME280, &mut pressure as &mut f32))?;
log::debug!("bme280 - reading humidity...");
esp!(bme280_read_humidity(BME280, &mut humidity as &mut f32))?;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an error from any of the three readings will cause get_readings to return an error.

}
log::debug!(
"temperature: {}, humidity: {}, pressure: {}",
temperature,
humidity,
pressure
);
let mut x: HashMap<String, f64> = HashMap::new();
x.insert("temperature_c".to_string(), temperature.into());
x.insert("humidity".to_string(), humidity.into());
x.insert("pressure_hpa".to_string(), pressure.into());
Ok(x)
}
}

impl Bme280 {
pub fn from_config(cfg: ConfigType, _deps: Vec<Dependency>) -> Result<SensorType, SensorError> {
// DO NOT use the board i2c interface to initialize the i2c bus, the idf-component will handle it
let bus_no = cfg
.get_attribute::<i32>("i2c_bus")
.inspect_err(|_| {
log::warn!("`i2c_bus` attribute not found or invalid, defaulting to bus 0")
})
.unwrap_or_default();

let sda_pin = cfg
.get_attribute::<i32>("sda_pin")
.inspect_err(|_| {
log::info!("`sda_pin` attribute not found or invalid, defaulting to pin 22")
})
.unwrap_or(22);
let scl_pin = cfg
.get_attribute::<i32>("scl_pin")
.inspect_err(|_| {
log::info!("`scl_pin` attribute not found or invalid, defaulting to pin 21")
})
.unwrap_or(21);

let config = i2c_config_t {
mode: I2C_MODE_MASTER,
sda_io_num: sda_pin,
sda_pullup_en: true,
scl_io_num: scl_pin,
scl_pullup_en: true,
__bindgen_anon_1: i2c_config_t__bindgen_ty_1 {
master: i2c_config_t__bindgen_ty_1__bindgen_ty_1 { clk_speed: 100000 },
},
clk_flags: 0,
};

unsafe {
log::info!("initializing I2C_BUS: {:?}", I2C_BUS);
I2C_BUS = i2c_bus_create(bus_no, &config);
log::info!("initialized I2C_BUS to : {:?}", I2C_BUS);
log::info!("initializing BME280: {:?}", BME280);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: create and init are different things for the bme280. be clear with logging....this log should probably read "creating"

BME280 = bme280_create(I2C_BUS, BME280_I2C_ADDRESS_DEFAULT.try_into().unwrap());
log::info!("initialized BME280 to : {:?}", BME280);
esp!(bme280_default_init(BME280))?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you have before/after log statements for everything but this init step, for consistency log here too

}
Ok(Arc::new(Mutex::new(Self {})))
}
}
Loading