diff options
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7b6f3e7 --- /dev/null +++ b/src/lib.rs | |||
| @@ -0,0 +1,435 @@ | |||
| 1 | //! BME690 Environmental Sensor Driver | ||
| 2 | //! | ||
| 3 | //! This is an AI-generated port of the official Bosch BME690 C driver to Rust. | ||
| 4 | //! Original C driver: https://github.com/boschsensortec/BME690_SensorAPI | ||
| 5 | //! | ||
| 6 | //! The BME690 is a digital environmental sensor that measures: | ||
| 7 | //! - Temperature (°C) | ||
| 8 | //! - Pressure (Pa) | ||
| 9 | //! - Humidity (%) | ||
| 10 | //! | ||
| 11 | //! This driver provides both blocking and async implementations using embedded-hal traits. | ||
| 12 | |||
| 13 | #![no_std] | ||
| 14 | |||
| 15 | /// I2C device address options | ||
| 16 | #[derive(Debug, Clone, Copy)] | ||
| 17 | pub enum DeviceAddr { | ||
| 18 | /// Primary address 0x76 (SDO connected to GND) | ||
| 19 | Primary, | ||
| 20 | /// Secondary address 0x77 (SDO connected to VDD) | ||
| 21 | Secondary, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl From<DeviceAddr> for u8 { | ||
| 25 | fn from(addr: DeviceAddr) -> Self { | ||
| 26 | match addr { | ||
| 27 | DeviceAddr::Primary => 0x76, | ||
| 28 | DeviceAddr::Secondary => 0x77, | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | impl From<DeviceAddr> for u16 { | ||
| 34 | fn from(addr: DeviceAddr) -> Self { | ||
| 35 | match addr { | ||
| 36 | DeviceAddr::Primary => 0x76, | ||
| 37 | DeviceAddr::Secondary => 0x77, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Temperature calibration coefficients | ||
| 43 | struct TempCalib { | ||
| 44 | par_t1: u16, | ||
| 45 | par_t2: u16, | ||
| 46 | par_t3: i8, | ||
| 47 | } | ||
| 48 | |||
| 49 | /// Pressure calibration coefficients | ||
| 50 | struct PressCalib { | ||
| 51 | par_p1: i16, | ||
| 52 | par_p2: u16, | ||
| 53 | par_p3: i8, | ||
| 54 | par_p4: i8, | ||
| 55 | par_p5: i16, | ||
| 56 | par_p6: i16, | ||
| 57 | par_p7: i8, | ||
| 58 | par_p8: i8, | ||
| 59 | par_p9: i16, | ||
| 60 | par_p10: i8, | ||
| 61 | par_p11: i8, | ||
| 62 | } | ||
| 63 | |||
| 64 | /// Humidity calibration coefficients | ||
| 65 | struct HumCalib { | ||
| 66 | par_h1: i16, | ||
| 67 | par_h2: i8, | ||
| 68 | par_h3: u8, | ||
| 69 | par_h4: i8, | ||
| 70 | par_h5: i16, | ||
| 71 | par_h6: u8, | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Sensor measurement data | ||
| 75 | #[derive(Debug, Clone, Copy)] | ||
| 76 | pub struct Measurement { | ||
| 77 | /// Temperature in degrees Celsius | ||
| 78 | pub temperature: f32, | ||
| 79 | /// Pressure in Pascals | ||
| 80 | pub pressure: f32, | ||
| 81 | /// Relative humidity in percent (0-100%) | ||
| 82 | pub humidity: f32, | ||
| 83 | } | ||
| 84 | |||
| 85 | type FieldData = [u8; 17]; // BME69X_LEN_FIELD from C driver | ||
| 86 | type CoeffData1 = [u8; 23]; // Coefficients from register 0x8a | ||
| 87 | type CoeffData2 = [u8; 14]; // Coefficients from register 0xe1 | ||
| 88 | type CoeffData3 = [u8; 5]; // Coefficients from register 0x00 | ||
| 89 | type CoeffDataAll = [u8; 42]; // Combined coefficient data | ||
| 90 | |||
| 91 | /// Combined calibration data for all sensors | ||
| 92 | struct Bme690Calib { | ||
| 93 | temp: TempCalib, | ||
| 94 | press: PressCalib, | ||
| 95 | hum: HumCalib, | ||
| 96 | } | ||
| 97 | |||
| 98 | /// Blocking BME690 driver | ||
| 99 | pub struct Bme690<I2C, D> { | ||
| 100 | i2c: I2C, | ||
| 101 | delay: D, | ||
| 102 | device_addr: u8, | ||
| 103 | calib: Bme690Calib, | ||
| 104 | } | ||
| 105 | |||
| 106 | /// Async BME690 driver | ||
| 107 | pub struct AsyncBme690<I2C, D> { | ||
| 108 | i2c: I2C, | ||
| 109 | delay: D, | ||
| 110 | device_addr: u8, | ||
| 111 | calib: Bme690Calib, | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Extract calibration coefficients from raw register data | ||
| 115 | fn extract_calibration(coeff: &CoeffDataAll) -> Bme690Calib { | ||
| 116 | // Extract temperature calibration (indices from bme69x_defs.h) | ||
| 117 | let par_t1 = u16::from_be_bytes([coeff[32], coeff[31]]); // IDX_DO_C_MSB=32, LSB=31 | ||
| 118 | let par_t2 = u16::from_be_bytes([coeff[1], coeff[0]]); // IDX_DTK1_C_MSB=1, LSB=0 | ||
| 119 | let par_t3 = coeff[2] as i8; // IDX_DTK2_C=2 | ||
| 120 | |||
| 121 | // Extract pressure calibration | ||
| 122 | let par_p1 = i16::from_be_bytes([coeff[11], coeff[10]]); // IDX_O_C_MSB=11, LSB=10 | ||
| 123 | let par_p2 = u16::from_be_bytes([coeff[13], coeff[12]]); // IDX_TK10_C_MSB=13, LSB=12 | ||
| 124 | let par_p3 = coeff[14] as i8; // IDX_TK20_C=14 | ||
| 125 | let par_p4 = coeff[15] as i8; // IDX_TK30_C=15 | ||
| 126 | let par_p5 = i16::from_be_bytes([coeff[5], coeff[4]]); // IDX_S_C_MSB=5, LSB=4 | ||
| 127 | let par_p6 = i16::from_be_bytes([coeff[7], coeff[6]]); // IDX_TK1S_C_MSB=7, LSB=6 | ||
| 128 | let par_p7 = coeff[8] as i8; // IDX_TK2S_C=8 | ||
| 129 | let par_p8 = coeff[9] as i8; // IDX_TK3S_C=9 | ||
| 130 | let par_p9 = i16::from_be_bytes([coeff[19], coeff[18]]); // IDX_NLS_C_MSB=19, LSB=18 | ||
| 131 | let par_p10 = coeff[20] as i8; // IDX_TKNLS_C=20 | ||
| 132 | let par_p11 = coeff[21] as i8; // IDX_NLS3_C=21 | ||
| 133 | |||
| 134 | // Extract humidity calibration (with sign conversion from C driver) | ||
| 135 | let mut par_h5 = ((coeff[23] as i16) << 4) | ((coeff[24] as i16) >> 4); // IDX_S_H_MSB=23, LSB=24 | ||
| 136 | if par_h5 > 2047 { | ||
| 137 | par_h5 -= 4096; | ||
| 138 | } | ||
| 139 | |||
| 140 | let mut par_h1 = ((coeff[25] as i16) << 4) | ((coeff[24] as i16) & 0x0F); // IDX_O_H_MSB=25, LSB=24 | ||
| 141 | if par_h1 > 2047 { | ||
| 142 | par_h1 -= 4096; | ||
| 143 | } | ||
| 144 | |||
| 145 | let par_h2 = coeff[26] as i8; // IDX_TK10H_C=26 | ||
| 146 | let par_h3 = coeff[28]; // IDX_par_h3=28 | ||
| 147 | let par_h4 = coeff[27] as i8; // IDX_par_h4=27 | ||
| 148 | let par_h6 = coeff[29]; // IDX_HLIN2_C=29 | ||
| 149 | |||
| 150 | Bme690Calib { | ||
| 151 | temp: TempCalib { par_t1, par_t2, par_t3 }, | ||
| 152 | press: PressCalib { | ||
| 153 | par_p1, par_p2, par_p3, par_p4, par_p5, | ||
| 154 | par_p6, par_p7, par_p8, par_p9, par_p10, par_p11, | ||
| 155 | }, | ||
| 156 | hum: HumCalib { par_h1, par_h2, par_h3, par_h4, par_h5, par_h6 }, | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /// Parse raw field data into calibrated measurements | ||
| 161 | fn parse_field_data(field_data: &FieldData, calib: &Bme690Calib) -> Measurement { | ||
| 162 | // Extract pressure (bytes 2-4, registers 0x1F-0x21) - matches C driver format | ||
| 163 | let pres_adc = ((field_data[2] as u32) << 16) | ||
| 164 | | ((field_data[3] as u32) << 8) | ||
| 165 | | (field_data[4] as u32); | ||
| 166 | |||
| 167 | // Extract temperature (bytes 5-7, registers 0x22-0x24) - matches C driver format | ||
| 168 | let temp_adc = ((field_data[5] as u32) << 16) | ||
| 169 | | ((field_data[6] as u32) << 8) | ||
| 170 | | (field_data[7] as u32); | ||
| 171 | |||
| 172 | // Extract humidity (bytes 8-9, registers 0x25-0x26) - matches C driver format | ||
| 173 | let hum_adc = ((field_data[8] as u16) << 8) | (field_data[9] as u16); | ||
| 174 | |||
| 175 | // Calculate compensated values | ||
| 176 | let temperature = calc_temperature(temp_adc, &calib.temp); | ||
| 177 | let pressure = calc_pressure(pres_adc, temperature, &calib.press); | ||
| 178 | let humidity = calc_humidity(hum_adc, temperature, &calib.hum); | ||
| 179 | |||
| 180 | Measurement { | ||
| 181 | temperature, | ||
| 182 | pressure, | ||
| 183 | humidity, | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | /// Calculate calibrated temperature from raw ADC value | ||
| 188 | /// Based on Bosch BME690 SDK floating-point implementation | ||
| 189 | fn calc_temperature(temp_adc: u32, calib: &TempCalib) -> f32 { | ||
| 190 | let do1 = (calib.par_t1 as i32) << 8; | ||
| 191 | let dtk1 = (calib.par_t2 as f64) / (1u64 << 30) as f64; | ||
| 192 | let dtk2 = (calib.par_t3 as f64) / (1u64 << 48) as f64; | ||
| 193 | |||
| 194 | let cf = temp_adc as i32 - do1; | ||
| 195 | let temp1 = cf as f64 * dtk1; | ||
| 196 | let temp2 = (cf as f64) * (cf as f64) * dtk2; | ||
| 197 | |||
| 198 | (temp1 + temp2) as f32 | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Calculate calibrated pressure from raw ADC value and temperature | ||
| 202 | /// Based on Bosch BME690 SDK floating-point implementation | ||
| 203 | fn calc_pressure(pres_adc: u32, temp: f32, calib: &PressCalib) -> f32 { | ||
| 204 | let o = (calib.par_p1 as u32) * (1u32 << 3); | ||
| 205 | let tk10 = (calib.par_p2 as f64) / (1u64 << 6) as f64; | ||
| 206 | let tk20 = (calib.par_p3 as f64) / (1u64 << 8) as f64; | ||
| 207 | let tk30 = (calib.par_p4 as f64) / (1u64 << 15) as f64; | ||
| 208 | |||
| 209 | let s = ((calib.par_p5 as f64) - (1u64 << 14) as f64) / (1u64 << 20) as f64; | ||
| 210 | let tk1s = ((calib.par_p6 as f64) - (1u64 << 14) as f64) / (1u64 << 29) as f64; | ||
| 211 | let tk2s = (calib.par_p7 as f64) / (1u64 << 32) as f64; | ||
| 212 | let tk3s = (calib.par_p8 as f64) / (1u64 << 37) as f64; | ||
| 213 | |||
| 214 | let nls = (calib.par_p9 as f64) / (1u64 << 48) as f64; | ||
| 215 | let tknls = (calib.par_p10 as f64) / (1u64 << 48) as f64; | ||
| 216 | // nls3 = par_p11 / 2^65, split into (2^35 * 2^30) to avoid overflow | ||
| 217 | let nls3 = (calib.par_p11 as f64) / ((1u64 << 35) as f64 * (1u64 << 30) as f64); | ||
| 218 | |||
| 219 | let temp = temp as f64; | ||
| 220 | let pres_adc = pres_adc as f64; | ||
| 221 | |||
| 222 | let tmp1 = o as f64 + (tk10 * temp) + (tk20 * temp * temp) + (tk30 * temp * temp * temp); | ||
| 223 | let tmp2 = pres_adc * (s + (tk1s * temp) + (tk2s * temp * temp) + (tk3s * temp * temp * temp)); | ||
| 224 | let tmp3 = pres_adc * pres_adc * (nls + (tknls * temp)); | ||
| 225 | let tmp4 = pres_adc * pres_adc * pres_adc * nls3; | ||
| 226 | |||
| 227 | (tmp1 + tmp2 + tmp3 + tmp4) as f32 | ||
| 228 | } | ||
| 229 | |||
| 230 | /// Calculate calibrated humidity from raw ADC value and temperature | ||
| 231 | /// Based on Bosch BME690 SDK floating-point implementation | ||
| 232 | fn calc_humidity(hum_adc: u16, temp: f32, calib: &HumCalib) -> f32 { | ||
| 233 | let temp_comp = (temp as f64 * 5120.0) - 76800.0; | ||
| 234 | |||
| 235 | let oh = (calib.par_h1 as f64) * (1u64 << 6) as f64; | ||
| 236 | let sh = (calib.par_h5 as f64) / (1u64 << 16) as f64; | ||
| 237 | let tk10h = (calib.par_h2 as f64) / (1u64 << 14) as f64; | ||
| 238 | let tk1sh = (calib.par_h4 as f64) / (1u64 << 26) as f64; | ||
| 239 | let tk2sh = (calib.par_h3 as f64) / (1u64 << 26) as f64; | ||
| 240 | let hlin2 = (calib.par_h6 as f64) / (1u64 << 19) as f64; | ||
| 241 | |||
| 242 | let hoff = (hum_adc as f64) - (oh + tk10h * temp_comp); | ||
| 243 | let hsens = hoff * sh * (1.0 + (tk1sh * temp_comp) + (tk1sh * tk2sh * temp_comp * temp_comp)); | ||
| 244 | let hum_float_val = hsens * (1.0 - hlin2 * hsens); | ||
| 245 | |||
| 246 | // Clamp to 0-100 range | ||
| 247 | hum_float_val.max(0.0).min(100.0) as f32 | ||
| 248 | } | ||
| 249 | |||
| 250 | // Blocking implementation | ||
| 251 | impl<I2C, D> Bme690<I2C, D> | ||
| 252 | where | ||
| 253 | I2C: embedded_hal::i2c::I2c, | ||
| 254 | D: embedded_hal::delay::DelayNs, | ||
| 255 | { | ||
| 256 | /// Create a new BME690 sensor instance | ||
| 257 | /// | ||
| 258 | /// # Arguments | ||
| 259 | /// * `i2c` - I2C peripheral | ||
| 260 | /// * `delay` - Delay provider | ||
| 261 | /// * `device_addr` - I2C address (Primary = 0x76, Secondary = 0x77) | ||
| 262 | pub fn new(mut i2c: I2C, delay: D, device_addr: impl Into<u8>) -> Result<Self, I2C::Error> { | ||
| 263 | let device_addr = device_addr.into(); | ||
| 264 | |||
| 265 | // Read calibration data - BME690 uses registers 0x8a, 0xe1, 0x00 | ||
| 266 | let mut coeff1 = CoeffData1::default(); | ||
| 267 | let mut coeff2 = CoeffData2::default(); | ||
| 268 | let mut coeff3 = CoeffData3::default(); | ||
| 269 | |||
| 270 | i2c.write_read(device_addr, &[0x8a], &mut coeff1)?; | ||
| 271 | i2c.write_read(device_addr, &[0xe1], &mut coeff2)?; | ||
| 272 | i2c.write_read(device_addr, &[0x00], &mut coeff3)?; | ||
| 273 | |||
| 274 | // Combine into single array like the C driver does | ||
| 275 | let mut coeff: CoeffDataAll = [0; 42]; | ||
| 276 | coeff[0..23].copy_from_slice(&coeff1); | ||
| 277 | coeff[23..37].copy_from_slice(&coeff2); | ||
| 278 | coeff[37..42].copy_from_slice(&coeff3); | ||
| 279 | |||
| 280 | let calib = extract_calibration(&coeff); | ||
| 281 | |||
| 282 | // Configure sensor | ||
| 283 | i2c.write(device_addr, &[0x72, 0x01])?; // CTRL_HUM - 1x oversampling | ||
| 284 | i2c.write(device_addr, &[0x74, 0x24])?; // CTRL_MEAS - sleep mode initially | ||
| 285 | |||
| 286 | Ok(Self { | ||
| 287 | i2c, | ||
| 288 | delay, | ||
| 289 | device_addr, | ||
| 290 | calib, | ||
| 291 | }) | ||
| 292 | } | ||
| 293 | |||
| 294 | fn trigger_measurement(&mut self) -> Result<(), I2C::Error> { | ||
| 295 | // Trigger forced mode measurement | ||
| 296 | self.i2c.write(self.device_addr, &[0x74, 0x25]) | ||
| 297 | } | ||
| 298 | |||
| 299 | fn wait_for_measurement(&mut self) -> Result<(), I2C::Error> { | ||
| 300 | loop { | ||
| 301 | let mut status = [0u8; 1]; | ||
| 302 | self.i2c.write_read(self.device_addr, &[0x1D], &mut status)?; | ||
| 303 | if status[0] & (1 << 7) != 0 { | ||
| 304 | break; // New data available | ||
| 305 | } | ||
| 306 | // Wait 10ms before polling again (BME690 typical measurement time) | ||
| 307 | self.delay.delay_ms(10); | ||
| 308 | } | ||
| 309 | Ok(()) | ||
| 310 | } | ||
| 311 | |||
| 312 | /// Perform a measurement and return temperature, pressure, and humidity | ||
| 313 | pub fn measure(&mut self) -> Measurement { | ||
| 314 | // Trigger measurement | ||
| 315 | self.trigger_measurement().unwrap(); | ||
| 316 | self.wait_for_measurement().unwrap(); | ||
| 317 | |||
| 318 | // Read all field data at once | ||
| 319 | let mut field_data = FieldData::default(); | ||
| 320 | self.i2c | ||
| 321 | .write_read(self.device_addr, &[0x1D], &mut field_data) | ||
| 322 | .unwrap(); | ||
| 323 | |||
| 324 | parse_field_data(&field_data, &self.calib) | ||
| 325 | } | ||
| 326 | |||
| 327 | /// Measure temperature only | ||
| 328 | pub fn measure_temperature(&mut self) -> f32 { | ||
| 329 | self.measure().temperature | ||
| 330 | } | ||
| 331 | |||
| 332 | /// Measure pressure only | ||
| 333 | pub fn measure_pressure(&mut self) -> f32 { | ||
| 334 | self.measure().pressure | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Measure humidity only | ||
| 338 | pub fn measure_humidity(&mut self) -> f32 { | ||
| 339 | self.measure().humidity | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | // Async implementation | ||
| 344 | impl<I2C, D> AsyncBme690<I2C, D> | ||
| 345 | where | ||
| 346 | I2C: embedded_hal_async::i2c::I2c, | ||
| 347 | D: embedded_hal_async::delay::DelayNs, | ||
| 348 | { | ||
| 349 | /// Create a new async BME690 sensor instance | ||
| 350 | /// | ||
| 351 | /// # Arguments | ||
| 352 | /// * `i2c` - Async I2C peripheral | ||
| 353 | /// * `delay` - Async delay provider | ||
| 354 | /// * `device_addr` - I2C address (Primary = 0x76, Secondary = 0x77) | ||
| 355 | pub async fn new(mut i2c: I2C, delay: D, device_addr: impl Into<u8>) -> Result<Self, I2C::Error> { | ||
| 356 | let device_addr = device_addr.into(); | ||
| 357 | |||
| 358 | // Read calibration data - BME690 uses registers 0x8a, 0xe1, 0x00 | ||
| 359 | let mut coeff1 = CoeffData1::default(); | ||
| 360 | let mut coeff2 = CoeffData2::default(); | ||
| 361 | let mut coeff3 = CoeffData3::default(); | ||
| 362 | |||
| 363 | i2c.write_read(device_addr, &[0x8a], &mut coeff1).await?; | ||
| 364 | i2c.write_read(device_addr, &[0xe1], &mut coeff2).await?; | ||
| 365 | i2c.write_read(device_addr, &[0x00], &mut coeff3).await?; | ||
| 366 | |||
| 367 | // Combine into single array like the C driver does | ||
| 368 | let mut coeff: CoeffDataAll = [0; 42]; | ||
| 369 | coeff[0..23].copy_from_slice(&coeff1); | ||
| 370 | coeff[23..37].copy_from_slice(&coeff2); | ||
| 371 | coeff[37..42].copy_from_slice(&coeff3); | ||
| 372 | |||
| 373 | let calib = extract_calibration(&coeff); | ||
| 374 | |||
| 375 | // Configure sensor | ||
| 376 | i2c.write(device_addr, &[0x72, 0x01]).await?; // CTRL_HUM - 1x oversampling | ||
| 377 | i2c.write(device_addr, &[0x74, 0x24]).await?; // CTRL_MEAS - sleep mode initially | ||
| 378 | |||
| 379 | Ok(Self { | ||
| 380 | i2c, | ||
| 381 | delay, | ||
| 382 | device_addr, | ||
| 383 | calib, | ||
| 384 | }) | ||
| 385 | } | ||
| 386 | |||
| 387 | async fn trigger_measurement(&mut self) -> Result<(), I2C::Error> { | ||
| 388 | // Trigger forced mode measurement | ||
| 389 | self.i2c.write(self.device_addr, &[0x74, 0x25]).await | ||
| 390 | } | ||
| 391 | |||
| 392 | async fn wait_for_measurement(&mut self) -> Result<(), I2C::Error> { | ||
| 393 | loop { | ||
| 394 | let mut status = [0u8; 1]; | ||
| 395 | self.i2c.write_read(self.device_addr, &[0x1D], &mut status).await?; | ||
| 396 | if status[0] & (1 << 7) != 0 { | ||
| 397 | break; // New data available | ||
| 398 | } | ||
| 399 | // Wait 10ms before polling again (BME690 typical measurement time) | ||
| 400 | self.delay.delay_ms(10).await; | ||
| 401 | } | ||
| 402 | Ok(()) | ||
| 403 | } | ||
| 404 | |||
| 405 | /// Perform an async measurement and return temperature, pressure, and humidity | ||
| 406 | pub async fn measure(&mut self) -> Measurement { | ||
| 407 | // Trigger measurement | ||
| 408 | self.trigger_measurement().await.unwrap(); | ||
| 409 | self.wait_for_measurement().await.unwrap(); | ||
| 410 | |||
| 411 | // Read all field data at once | ||
| 412 | let mut field_data = FieldData::default(); | ||
| 413 | self.i2c | ||
| 414 | .write_read(self.device_addr, &[0x1D], &mut field_data) | ||
| 415 | .await | ||
| 416 | .unwrap(); | ||
| 417 | |||
| 418 | parse_field_data(&field_data, &self.calib) | ||
| 419 | } | ||
| 420 | |||
| 421 | /// Measure temperature only (async) | ||
| 422 | pub async fn measure_temperature(&mut self) -> f32 { | ||
| 423 | self.measure().await.temperature | ||
| 424 | } | ||
| 425 | |||
| 426 | /// Measure pressure only (async) | ||
| 427 | pub async fn measure_pressure(&mut self) -> f32 { | ||
| 428 | self.measure().await.pressure | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Measure humidity only (async) | ||
| 432 | pub async fn measure_humidity(&mut self) -> f32 { | ||
| 433 | self.measure().await.humidity | ||
| 434 | } | ||
| 435 | } | ||
