Skip to main content

bme280_rs/
async.rs

1// Copyright Claudio Mattera 2022-2026.
2//
3// Distributed under the MIT License or the Apache 2.0 License at your option.
4// See the accompanying files LICENSE-MIT.txt and LICENSE-APACHE-2.0.txt, or
5// online at
6// https://opensource.org/licenses/MIT
7// https://opensource.org/licenses/Apache-2.0
8
9//! Data types and functions for BME280 sensor interface
10
11use embedded_hal_async::delay::DelayNs;
12use embedded_hal_async::i2c::I2c;
13
14use crate::calibration;
15use crate::constants::BME280_COMMAND_SOFTRESET;
16use crate::constants::BME280_REGISTER_CHIPID;
17use crate::constants::BME280_REGISTER_CONFIG;
18use crate::constants::BME280_REGISTER_CONTROL;
19use crate::constants::BME280_REGISTER_CONTROLHUMID;
20use crate::constants::BME280_REGISTER_HUMIDDATA;
21use crate::constants::BME280_REGISTER_PRESSUREDATA;
22use crate::constants::BME280_REGISTER_SOFTRESET;
23use crate::constants::BME280_REGISTER_STATUS;
24use crate::constants::BME280_REGISTER_TEMPDATA;
25use crate::constants::DEFAULT_ADDRESS;
26use crate::constants::MODE_SLEEP;
27use crate::constants::SKIPPED_HUMIDITY_OUTPUT;
28use crate::constants::SKIPPED_PRESSURE_OUTPUT;
29use crate::constants::SKIPPED_TEMPERATURE_OUTPUT;
30use crate::macros::debug;
31use crate::macros::warn;
32use crate::sample::humidity_from_number;
33use crate::sample::pressure_from_pascal;
34use crate::sample::temperature_from_celsius;
35use crate::sample::Humidity;
36use crate::sample::Pressure;
37use crate::sample::RawSample;
38use crate::sample::Sample;
39use crate::sample::Temperature;
40use crate::CalibrationData;
41use crate::Configuration;
42use crate::Status;
43
44/// Async interface to BME280 sensor over I²C
45pub struct Bme280<I2c, Delay> {
46    /// I²C device
47    i2c: I2c,
48
49    /// I²C address
50    address: u8,
51
52    /// Delay function
53    delay: Delay,
54
55    /// Calibration coefficients
56    coefficients: CalibrationData,
57
58    /// Sensor configuration
59    configuration: Configuration,
60}
61
62impl<I2C, D> Bme280<I2C, D>
63where
64    I2C: I2c,
65    D: DelayNs,
66{
67    /// Create a new sensor using an I²C interface and a delay function using
68    /// the sensor's default address [`DEFAULT_ADDRESS`])
69    pub fn new(i2c: I2C, delay: D) -> Self {
70        Self::new_with_address(i2c, DEFAULT_ADDRESS, delay)
71    }
72
73    /// Release the I²C interface
74    pub fn release(self) -> I2C {
75        self.i2c
76    }
77
78    /// Create a new sensor using an I²C interface and a delay function
79    pub fn new_with_address(i2c: I2C, address: u8, delay: D) -> Self {
80        Self::new_with_coefficients(i2c, address, delay, CalibrationData::default())
81    }
82
83    /// Create a new sensor with specific calibration coefficients
84    fn new_with_coefficients(
85        i2c: I2C,
86        address: u8,
87        delay: D,
88        coefficients: CalibrationData,
89    ) -> Self {
90        debug!("Creating new BME280 device at address 0x{:x}", address);
91        Self {
92            i2c,
93            address,
94            delay,
95            coefficients,
96            configuration: Configuration::default(),
97        }
98    }
99
100    /// Initialize the sensor
101    ///
102    /// Send a soft-reset signal, obtain the calibration coefficients, and set
103    /// default sampling configuration.
104    ///
105    /// Note that the default sampling configuration disables measurement of
106    /// temperature, pressure and humidity.
107    ///
108    /// # Errors
109    ///
110    /// Return an error if it cannot communicate with the sensor.
111    pub async fn init(&mut self) -> Result<(), I2C::Error> {
112        debug!("Sending soft-reset signal");
113        self.write_u8(BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET)
114            .await?;
115
116        debug!("Waiting 10 ms");
117        self.delay.delay_ms(10).await;
118
119        while self.status().await?.is_calibrating() {
120            debug!("Calibration not complete, waiting 10 ms");
121            self.delay.delay_ms(10).await;
122        }
123
124        debug!("Reading coefficients");
125        self.read_calibration_coefficients().await?;
126
127        debug!("Set sampling");
128        let configuration = Configuration::default();
129        self.set_sampling_configuration(configuration).await?;
130
131        debug!("Waiting 100 ms");
132        self.delay.delay_ms(100).await;
133
134        Ok(())
135    }
136
137    /// Obtain the chip id
138    ///
139    /// The chip id is always [`crate::constants::CHIP_ID`], so this function
140    /// can be used to validate that communication with the chip works fine.
141    ///
142    /// # Errors
143    ///
144    /// Return an error if it cannot communicate with the sensor.
145    pub async fn chip_id(&mut self) -> Result<u8, I2C::Error> {
146        debug!("Read chip id");
147        let chip_id = self.read_u8(BME280_REGISTER_CHIPID).await?;
148
149        Ok(chip_id)
150    }
151
152    /// Obtain the chip status
153    ///
154    /// # Errors
155    ///
156    /// Return an error if it cannot communicate with the sensor.
157    pub async fn status(&mut self) -> Result<Status, I2C::Error> {
158        debug!("Read chip status");
159        let status = self.read_u8(BME280_REGISTER_STATUS).await?.into();
160
161        Ok(status)
162    }
163
164    /// Set the sampling configuration
165    ///
166    /// # Errors
167    ///
168    /// Return an error if it cannot communicate with the sensor.
169    pub async fn set_sampling_configuration(
170        &mut self,
171        configuration: Configuration,
172    ) -> Result<(), I2C::Error> {
173        self.configuration = configuration;
174
175        let (config, ctrl_meas, ctrl_hum) = self.configuration.to_lowlevel_configuration();
176
177        // making sure sensor is in sleep mode before setting configuration
178        // as it otherwise may be ignored
179        self.write_u8(BME280_REGISTER_CONTROL, MODE_SLEEP).await?;
180
181        // you must make sure to also set REGISTER_CONTROL after setting the
182        // CONTROLHUMID register, otherwise the values won't be applied (see
183        // DS 5.4.3)
184        self.write_u8(BME280_REGISTER_CONTROLHUMID, ctrl_hum.into())
185            .await?;
186        self.write_u8(BME280_REGISTER_CONFIG, config.into()).await?;
187        self.write_u8(BME280_REGISTER_CONTROL, ctrl_meas.into())
188            .await?;
189
190        Ok(())
191    }
192
193    /// Take a forced measurement
194    ///
195    /// When the chip is set to work in forced mode, it goes back to sleep
196    /// after every measurement.
197    /// It must be set again to forced mode in order to force a new
198    /// measurement.
199    ///
200    /// # Errors
201    ///
202    /// Return an error if it cannot communicate with the sensor.
203    pub async fn take_forced_measurement(&mut self) -> Result<bool, I2C::Error> {
204        if self.configuration.is_forced() {
205            debug!("Forcing taking a measurement");
206
207            let (_config, ctrl_meas, _ctrl_hum) = self.configuration.to_lowlevel_configuration();
208            self.write_u8(BME280_REGISTER_CONTROL, ctrl_meas.into())
209                .await?;
210
211            for _ in 0..10 {
212                if !self.status().await?.is_measuring() {
213                    break;
214                }
215
216                debug!("Measuring not complete, waiting 10 ms");
217                self.delay.delay_ms(10).await;
218            }
219
220            Ok(true)
221        } else {
222            Ok(false)
223        }
224    }
225
226    /// Read a raw sample from sensor
227    ///
228    /// Raw sample must be converted to human-readable quantities using
229    /// compensation formulas from the data sheet.
230    async fn read_raw_sample(&mut self) -> Result<RawSample, I2C::Error> {
231        let buffer: [u8; 1] = [BME280_REGISTER_PRESSUREDATA];
232        let mut buf: [u8; 8] = [0; 8];
233        self.i2c.write_read(self.address, &buffer, &mut buf).await?;
234
235        // msb [7:0] = p[19:12]
236        // lsb [7:0] = p[11:4]
237        // xlsb[7:4] = p[3:0]
238        let adc_p: u32 =
239            (u32::from(buf[0]) << 12) | (u32::from(buf[1]) << 4) | (u32::from(buf[2]) >> 4);
240        // msb [7:0] = t[19:12]
241        // lsb [7:0] = t[11:4]
242        // xlsb[7:4] = t[3:0]
243        let adc_t: u32 =
244            (u32::from(buf[3]) << 12) | (u32::from(buf[4]) << 4) | (u32::from(buf[5]) >> 4);
245        // msb [7:0] = h[15:8]
246        // lsb [7:0] = h[7:0]
247        let adc_h: u16 = (u16::from(buf[6]) << 8) | u16::from(buf[7]);
248
249        Ok(RawSample {
250            adc_t: if adc_t == SKIPPED_TEMPERATURE_OUTPUT {
251                None
252            } else {
253                Some(adc_t)
254            },
255            adc_p: if adc_p == SKIPPED_PRESSURE_OUTPUT {
256                None
257            } else {
258                Some(adc_p)
259            },
260            adc_h: if adc_h == SKIPPED_HUMIDITY_OUTPUT {
261                None
262            } else {
263                Some(adc_h)
264            },
265        })
266    }
267
268    /// Read a sample of temperature, pressure and humidity
269    ///
270    /// Measures that are disabled in the sampling configuration have value
271    /// `None`.
272    ///
273    /// # Errors
274    ///
275    /// Return an error if it cannot communicate with the sensor.
276    pub async fn read_sample(&mut self) -> Result<Sample, I2C::Error> {
277        let RawSample {
278            adc_t,
279            adc_p,
280            adc_h,
281        } = self.read_raw_sample().await?;
282
283        if let Some(adc_t) = adc_t {
284            let t_fine = self.coefficients.compensate_temperature(adc_t);
285            let t = Some(Self::temperature_fine_to_temperature(t_fine));
286            let p = adc_p.map(|adc_p| self.coefficients.compensate_pressure(adc_p, t_fine));
287            let h = adc_h.map(|adc_h| self.coefficients.compensate_humidity(adc_h, t_fine));
288
289            let temperature = t;
290
291            #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
292            let pressure = p.map(|p| p as f32 / 256.0);
293            let pressure = pressure.map(pressure_from_pascal);
294            #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
295            let humidity = h.map(|h| h as f32 / 1024.0);
296            let humidity = humidity.map(humidity_from_number);
297
298            Ok(Sample {
299                temperature,
300                pressure,
301                humidity,
302            })
303        } else {
304            warn!("Temperature measurement is disabled");
305
306            Ok(Sample::default())
307        }
308    }
309
310    /// Compute raw temperature from human-readable temperature
311    fn temperature_fine_to_temperature(t_fine: i32) -> Temperature {
312        let t = (t_fine * 5 + 128) >> 8;
313
314        #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
315        let t = t as f32;
316
317        temperature_from_celsius(t / 100.0)
318    }
319
320    /// Read a sample of temperature
321    ///
322    /// If temperature is disabled in the sampling configuration, return `None`.
323    ///
324    /// # Errors
325    ///
326    /// Return an error if it cannot communicate with the sensor.
327    pub async fn read_temperature(&mut self) -> Result<Option<Temperature>, I2C::Error> {
328        if let Some(t_fine) = self.read_temperature_fine().await? {
329            Ok(Some(Self::temperature_fine_to_temperature(t_fine)))
330        } else {
331            Ok(None)
332        }
333    }
334
335    /// Read temperature from sensor
336    async fn read_temperature_fine(&mut self) -> Result<Option<i32>, I2C::Error> {
337        let adc_t = self.read_raw_temperature().await?;
338        let t_fine = adc_t.map(|adc_t| self.coefficients.compensate_temperature(adc_t));
339        Ok(t_fine)
340    }
341
342    /// Read raw temperature from sensor
343    ///
344    /// Raw temperature must be converted to human-readable temperature using
345    /// compensation formulas from the data sheet.
346    async fn read_raw_temperature(&mut self) -> Result<Option<u32>, I2C::Error> {
347        let adc_t = self.read_u24(BME280_REGISTER_TEMPDATA).await?;
348
349        if adc_t == SKIPPED_TEMPERATURE_OUTPUT {
350            Ok(None)
351        } else {
352            Ok(Some(adc_t))
353        }
354    }
355
356    /// Read a sample of pressure
357    ///
358    /// The temperature value, necessary to compute the compensated pressure
359    /// value, is also read from the sensor.
360    ///
361    /// If pressure is disabled in the sampling configuration, return `None`.
362    ///
363    /// # Errors
364    ///
365    /// Return an error if it cannot communicate with the sensor.
366    pub async fn read_pressure(&mut self) -> Result<Option<Pressure>, I2C::Error> {
367        if let Some(t_fine) = self.read_temperature_fine().await? {
368            self.read_pressure_with_temperature_fine(t_fine).await
369        } else {
370            warn!("Pressure measurement is disabled");
371            Ok(None)
372        }
373    }
374
375    /// Read a sample of pressure with a user-specified temperature value
376    ///
377    /// Unlike in [`Self::read_pressure()`], this function does not take the
378    /// temperature from the sensor, so it can be used if the temperature
379    /// is already known.
380    ///
381    /// If pressure is disabled in the sampling configuration, return `None`.
382    ///
383    /// # Errors
384    ///
385    /// Return an error if it cannot communicate with the sensor.
386    pub async fn read_pressure_with_temperature(
387        &mut self,
388        temperature: f32,
389    ) -> Result<Option<Pressure>, I2C::Error> {
390        #[allow(clippy::cast_possible_truncation)] // Acceptable truncation
391        let t = (temperature * 100.0) as i32;
392        let t_fine = ((t << 8) - 128) / 5;
393        self.read_pressure_with_temperature_fine(t_fine).await
394    }
395
396    /// Read pressure from sensor using specific temperature reference
397    async fn read_pressure_with_temperature_fine(
398        &mut self,
399        t_fine: i32,
400    ) -> Result<Option<Pressure>, I2C::Error> {
401        let adc_p = self.read_raw_pressure().await?;
402        let p = adc_p.map(|adc_p| {
403            let p = self.coefficients.compensate_pressure(adc_p, t_fine);
404
405            #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
406            let p = p as f32;
407
408            pressure_from_pascal(p / 256.0)
409        });
410        Ok(p)
411    }
412
413    /// Read raw pressure from sensor
414    ///
415    /// Raw pressure must be converted to human-readable pressure using
416    /// compensation formulas from the data sheet.
417    async fn read_raw_pressure(&mut self) -> Result<Option<u32>, I2C::Error> {
418        let adc_p = self.read_u24(BME280_REGISTER_PRESSUREDATA).await?;
419
420        if adc_p == SKIPPED_PRESSURE_OUTPUT {
421            Ok(None)
422        } else {
423            Ok(Some(adc_p))
424        }
425    }
426
427    /// Read a sample of humidity
428    ///
429    /// The temperature value, necessary to compute the compensated pressure
430    /// value, is also read from the sensor.
431    ///
432    /// If humidity is disabled in the sampling configuration, return `None`.
433    ///
434    /// # Errors
435    ///
436    /// Return an error if it cannot communicate with the sensor.
437    pub async fn read_humidity(&mut self) -> Result<Option<Humidity>, I2C::Error> {
438        if let Some(t_fine) = self.read_temperature_fine().await? {
439            self.read_humidity_with_temperature_fine(t_fine).await
440        } else {
441            warn!("Humidity measurement is disabled");
442            Ok(None)
443        }
444    }
445
446    /// Read a sample of humidity with a user-specified temperature value
447    ///
448    /// Unlike in [`Self::read_humidity()`], this function does not take the
449    /// temperature from the sensor, so it can be used if the temperature
450    /// is already known.
451    ///
452    /// If humidity is disabled in the sampling configuration, return `None`.
453    ///
454    /// # Errors
455    ///
456    /// Return an error if it cannot communicate with the sensor.
457    pub async fn read_humidity_with_temperature(
458        &mut self,
459        temperature: f32,
460    ) -> Result<Option<Humidity>, I2C::Error> {
461        #[allow(clippy::cast_possible_truncation)] // Acceptable truncation
462        let t = (temperature * 100.0) as i32;
463        let t_fine = ((t << 8) - 128) / 5;
464        self.read_humidity_with_temperature_fine(t_fine).await
465    }
466
467    /// Read humidity from sensor using specific reference temperature
468    async fn read_humidity_with_temperature_fine(
469        &mut self,
470        t_fine: i32,
471    ) -> Result<Option<Humidity>, I2C::Error> {
472        let adc_h = self.read_raw_humidity().await?;
473        let h = adc_h.map(|adc_h| {
474            let h = self.coefficients.compensate_humidity(adc_h, t_fine);
475
476            #[allow(clippy::cast_precision_loss)] // Acceptable precision loss
477            let h = h as f32;
478
479            humidity_from_number(h / 1024.0)
480        });
481        Ok(h)
482    }
483
484    /// Read raw humidity from sensor
485    ///
486    /// Raw humidity must be converted to human-readable humidity using
487    /// compensation formulas from the data sheet.
488    async fn read_raw_humidity(&mut self) -> Result<Option<u16>, I2C::Error> {
489        let adc_h = self.read_u16(BME280_REGISTER_HUMIDDATA).await?;
490
491        if adc_h == SKIPPED_HUMIDITY_OUTPUT {
492            Ok(None)
493        } else {
494            Ok(Some(adc_h))
495        }
496    }
497
498    /// Read calibration coefficients from sensor
499    async fn read_calibration_coefficients(&mut self) -> Result<(), I2C::Error> {
500        let buffer: [u8; 1] = [calibration::FIRST_REGISTER];
501
502        let mut out: [u8; calibration::TOTAL_LENGTH] = [0; calibration::TOTAL_LENGTH];
503        self.i2c
504            .write_read(
505                self.address,
506                &buffer,
507                &mut out[0..calibration::FIRST_LENGTH],
508            )
509            .await?;
510
511        let buffer: [u8; 1] = [calibration::SECOND_REGISTER];
512        self.i2c
513            .write_read(
514                self.address,
515                &buffer,
516                &mut out[calibration::FIRST_LENGTH..calibration::TOTAL_LENGTH],
517            )
518            .await?;
519
520        self.coefficients = (&out).into();
521
522        Ok(())
523    }
524
525    /// Write an unsigned byte to an I²C register
526    async fn write_u8(&mut self, register: u8, value: u8) -> Result<(), I2C::Error> {
527        let buffer: [u8; 2] = [register, value];
528        self.i2c.write(self.address, &buffer).await?;
529        Ok(())
530    }
531
532    /// Write an unsigned byte from an I²C register
533    async fn read_u8(&mut self, register: u8) -> Result<u8, I2C::Error> {
534        let buffer: [u8; 1] = [register];
535        let mut output_buffer: [u8; 1] = [0];
536        self.i2c
537            .write_read(self.address, &buffer, &mut output_buffer)
538            .await?;
539        Ok(output_buffer[0])
540    }
541
542    /// Write two unsigned bytes to an I²C register
543    async fn read_u16(&mut self, register: u8) -> Result<u16, I2C::Error> {
544        let buffer: [u8; 1] = [register];
545        let mut output_buffer: [u8; 2] = [0, 0];
546        self.i2c
547            .write_read(self.address, &buffer, &mut output_buffer)
548            .await?;
549        Ok((u16::from(output_buffer[0]) << 8) | u16::from(output_buffer[1]))
550    }
551
552    /// Write three unsigned bytes to an I²C register
553    async fn read_u24(&mut self, register: u8) -> Result<u32, I2C::Error> {
554        let buffer: [u8; 1] = [register];
555        let mut output_buffer: [u8; 3] = [0, 0, 0];
556        self.i2c
557            .write_read(self.address, &buffer, &mut output_buffer)
558            .await?;
559        Ok((u32::from(output_buffer[0]) << 12)
560            | (u32::from(output_buffer[1]) << 4)
561            | (u32::from(output_buffer[2]) >> 4))
562    }
563}
564
565#[cfg(test)]
566mod tests {
567    #![allow(clippy::panic_in_result_fn)]
568
569    use alloc::vec;
570
571    use embedded_hal::i2c::ErrorKind;
572
573    use embedded_hal_mock::eh1::delay::NoopDelay as DelayMock;
574    use embedded_hal_mock::eh1::i2c::Mock as I2cMock;
575    use embedded_hal_mock::eh1::i2c::Transaction as I2cTransaction;
576
577    use crate::calibration::TEST_CALIBRATION_DATA;
578    use crate::constants::CHIP_ID;
579
580    use super::*;
581
582    #[tokio::test]
583    async fn test_init() -> Result<(), ErrorKind> {
584        let expectations = [
585            // Reset sensor
586            I2cTransaction::write(
587                DEFAULT_ADDRESS,
588                vec![BME280_REGISTER_SOFTRESET, BME280_COMMAND_SOFTRESET],
589            ),
590            // Wait for calibration
591            I2cTransaction::write_read(
592                DEFAULT_ADDRESS,
593                vec![BME280_REGISTER_STATUS],
594                vec![0b0000_0001],
595            ),
596            // Wait for calibration
597            I2cTransaction::write_read(
598                DEFAULT_ADDRESS,
599                vec![BME280_REGISTER_STATUS],
600                vec![0b0000_0000],
601            ),
602            // Read coefficients
603            I2cTransaction::write_read(
604                DEFAULT_ADDRESS,
605                vec![calibration::FIRST_REGISTER],
606                vec![0; 26],
607            ),
608            I2cTransaction::write_read(
609                DEFAULT_ADDRESS,
610                vec![calibration::SECOND_REGISTER],
611                vec![0; 7],
612            ),
613            // Configure sensor
614            I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROL, MODE_SLEEP]),
615            I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROLHUMID, 0]),
616            I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONFIG, 0]),
617            I2cTransaction::write(DEFAULT_ADDRESS, vec![BME280_REGISTER_CONTROL, 0]),
618        ];
619        let i2c = I2cMock::new(&expectations);
620
621        let mut bme280 = Bme280::new(i2c, DelayMock);
622
623        bme280.init().await?;
624
625        bme280.release().done();
626
627        Ok(())
628    }
629
630    #[tokio::test]
631    async fn test_chip_id() -> Result<(), ErrorKind> {
632        let expectations = [I2cTransaction::write_read(
633            DEFAULT_ADDRESS,
634            vec![BME280_REGISTER_CHIPID],
635            vec![CHIP_ID],
636        )];
637        let i2c = I2cMock::new(&expectations);
638
639        let mut bme280 = Bme280::new(i2c, DelayMock);
640
641        let chip_id = bme280.chip_id().await?;
642
643        assert_eq!(chip_id, CHIP_ID);
644
645        bme280.release().done();
646        Ok(())
647    }
648
649    #[tokio::test]
650    async fn test_chip_status() -> Result<(), ErrorKind> {
651        let expectations = [I2cTransaction::write_read(
652            DEFAULT_ADDRESS,
653            vec![BME280_REGISTER_STATUS],
654            vec![0x00],
655        )];
656        let i2c = I2cMock::new(&expectations);
657
658        let mut bme280 = Bme280::new(i2c, DelayMock);
659
660        let status = bme280.status().await?;
661
662        assert!(!status.is_measuring());
663        assert!(!status.is_calibrating());
664
665        bme280.release().done();
666        Ok(())
667    }
668
669    #[tokio::test]
670    async fn test_chip_status_measuring() -> Result<(), ErrorKind> {
671        let expectations = [I2cTransaction::write_read(
672            DEFAULT_ADDRESS,
673            vec![BME280_REGISTER_STATUS],
674            vec![0b0000_0100],
675        )];
676        let i2c = I2cMock::new(&expectations);
677
678        let mut bme280 = Bme280::new(i2c, DelayMock);
679
680        let status = bme280.status().await?;
681
682        assert!(status.is_measuring());
683        assert!(!status.is_calibrating());
684
685        bme280.release().done();
686        Ok(())
687    }
688
689    #[tokio::test]
690    async fn test_read_temperature_disabled() -> Result<(), ErrorKind> {
691        let expectations = [I2cTransaction::write_read(
692            DEFAULT_ADDRESS,
693            vec![BME280_REGISTER_TEMPDATA],
694            vec![0x80, 0x00, 0x00],
695        )];
696        let i2c = I2cMock::new(&expectations);
697
698        let mut bme280 = Bme280::new_with_coefficients(
699            i2c,
700            DEFAULT_ADDRESS,
701            DelayMock,
702            TEST_CALIBRATION_DATA.clone(),
703        );
704
705        let expected = None;
706
707        let temperature = bme280.read_temperature().await?;
708
709        assert_eq!(temperature, expected);
710
711        bme280.release().done();
712        Ok(())
713    }
714
715    #[tokio::test]
716    async fn test_read_temperature() -> Result<(), ErrorKind> {
717        let expectations = [I2cTransaction::write_read(
718            DEFAULT_ADDRESS,
719            vec![BME280_REGISTER_TEMPDATA],
720            vec![0x84, 0x47, 0x00],
721        )];
722        let i2c = I2cMock::new(&expectations);
723
724        let mut bme280 = Bme280::new_with_coefficients(
725            i2c,
726            DEFAULT_ADDRESS,
727            DelayMock,
728            TEST_CALIBRATION_DATA.clone(),
729        );
730
731        let expected = Some(temperature_from_celsius(27.33));
732
733        let temperature = bme280.read_temperature().await?;
734
735        assert_eq!(temperature, expected);
736
737        bme280.release().done();
738        Ok(())
739    }
740
741    #[tokio::test]
742    async fn test_read_pressure_disabled() -> Result<(), ErrorKind> {
743        let expectations = [
744            I2cTransaction::write_read(
745                DEFAULT_ADDRESS,
746                vec![BME280_REGISTER_TEMPDATA],
747                vec![0x84, 0x47, 0x00],
748            ),
749            I2cTransaction::write_read(
750                DEFAULT_ADDRESS,
751                vec![BME280_REGISTER_PRESSUREDATA],
752                vec![0x80, 0x00, 0x00],
753            ),
754        ];
755        let i2c = I2cMock::new(&expectations);
756
757        let mut bme280 = Bme280::new_with_coefficients(
758            i2c,
759            DEFAULT_ADDRESS,
760            DelayMock,
761            TEST_CALIBRATION_DATA.clone(),
762        );
763
764        let expected = None;
765
766        let pressure = bme280.read_pressure().await?;
767
768        assert_eq!(pressure, expected);
769
770        bme280.release().done();
771        Ok(())
772    }
773
774    #[tokio::test]
775    async fn test_read_pressure() -> Result<(), ErrorKind> {
776        let expectations = [
777            I2cTransaction::write_read(
778                DEFAULT_ADDRESS,
779                vec![BME280_REGISTER_TEMPDATA],
780                vec![0x84, 0x47, 0x00],
781            ),
782            I2cTransaction::write_read(
783                DEFAULT_ADDRESS,
784                vec![BME280_REGISTER_PRESSUREDATA],
785                vec![0x4f, 0x50, 0x00],
786            ),
787        ];
788        let i2c = I2cMock::new(&expectations);
789
790        let mut bme280 = Bme280::new_with_coefficients(
791            i2c,
792            DEFAULT_ADDRESS,
793            DelayMock,
794            TEST_CALIBRATION_DATA.clone(),
795        );
796
797        let expected = Some(pressure_from_pascal(101_233.016));
798
799        let pressure = bme280.read_pressure().await?;
800
801        assert_eq!(pressure, expected);
802
803        bme280.release().done();
804        Ok(())
805    }
806
807    #[tokio::test]
808    async fn test_read_humidity_disabled() -> Result<(), ErrorKind> {
809        let expectations = [
810            I2cTransaction::write_read(
811                DEFAULT_ADDRESS,
812                vec![BME280_REGISTER_TEMPDATA],
813                vec![0x84, 0x47, 0x00],
814            ),
815            I2cTransaction::write_read(
816                DEFAULT_ADDRESS,
817                vec![BME280_REGISTER_HUMIDDATA],
818                vec![0x80, 0x00],
819            ),
820        ];
821        let i2c = I2cMock::new(&expectations);
822
823        let mut bme280 = Bme280::new_with_coefficients(
824            i2c,
825            DEFAULT_ADDRESS,
826            DelayMock,
827            TEST_CALIBRATION_DATA.clone(),
828        );
829
830        let expected = None;
831
832        let humidity = bme280.read_humidity().await?;
833
834        assert_eq!(humidity, expected);
835
836        bme280.release().done();
837        Ok(())
838    }
839
840    #[tokio::test]
841    async fn test_read_humidity() -> Result<(), ErrorKind> {
842        let expectations = [
843            I2cTransaction::write_read(
844                DEFAULT_ADDRESS,
845                vec![BME280_REGISTER_TEMPDATA],
846                vec![0x84, 0x47, 0x00],
847            ),
848            I2cTransaction::write_read(
849                DEFAULT_ADDRESS,
850                vec![BME280_REGISTER_HUMIDDATA],
851                vec![0x60, 0x02],
852            ),
853        ];
854        let i2c = I2cMock::new(&expectations);
855
856        let mut bme280 = Bme280::new_with_coefficients(
857            i2c,
858            DEFAULT_ADDRESS,
859            DelayMock,
860            TEST_CALIBRATION_DATA.clone(),
861        );
862
863        let expected = Some(humidity_from_number(34.854_492));
864
865        let humidity = bme280.read_humidity().await?;
866
867        assert_eq!(humidity, expected);
868
869        bme280.release().done();
870        Ok(())
871    }
872}