Skip to main content

embedded_sensors_hal/
humidity.rs

1//! Blocking Humidity Sensor API
2//!
3//! This API provides generic methods for interfacing with humidity sensors specifically.
4//!
5//! # For HAL authors
6//!
7//! Here is an example for the implementation of the RelativeHumiditySensor trait for a humidity sensor.
8//!
9//! ```
10//! use embedded_sensors_hal::sensor;
11//! use embedded_sensors_hal::humidity::{RelativeHumiditySensor, Percentage};
12//!
13//! // A struct representing a humidity sensor.
14//! pub struct MyHumiditySensor {
15//!     // ...
16//! }
17//!
18//! #[derive(Clone, Copy, Debug)]
19//! pub enum Error {
20//!     // ...
21//! }
22//!
23//! impl sensor::Error for Error {
24//!     fn kind(&self) -> sensor::ErrorKind {
25//!         match *self {
26//!             // ...
27//!         }
28//!     }
29//! }
30//!
31//! impl sensor::ErrorType for MyHumiditySensor {
32//!     type Error = Error;
33//! }
34//!
35//! impl RelativeHumiditySensor for MyHumiditySensor {
36//!     fn relative_humidity(&mut self) -> Result<Percentage, Self::Error> {
37//!         // ...
38//!         Ok(42.0)
39//!     }
40//! }
41//! ```
42
43use crate::decl_threshold_traits;
44use crate::sensor::ErrorType;
45
46/// Associates the units relative humidity (RH) samples are measured in with the underlying data type.
47pub type Percentage = f32;
48
49/// Blocking Relative Humidity Sensor methods.
50pub trait RelativeHumiditySensor: ErrorType {
51    /// Returns a relative humidity (RH) sample as a percentage.
52    fn relative_humidity(&mut self) -> Result<Percentage, Self::Error>;
53}
54
55impl<T: RelativeHumiditySensor + ?Sized> RelativeHumiditySensor for &mut T {
56    #[inline]
57    fn relative_humidity(&mut self) -> Result<Percentage, Self::Error> {
58        T::relative_humidity(self)
59    }
60}
61
62// This macro generates the following blocking threshold traits:
63//
64// pub trait RelativeHumidityThresholdSet: RelativeHumiditySensor {
65//     fn set_relative_humidity_threshold_low(&mut self, threshold: Percentage) -> Result<(), Self::Error>;
66//     fn set_relative_humidity_threshold_high(&mut self, threshold: Percentage) -> Result<(), Self::Error>;
67// }
68//
69// pub trait RelativeHumidityHysteresis: RelativeHumidityThresholdSet {
70//     fn set_relative_humidity_threshold_hysteresis(&mut self, hysteresis: Percentage) -> Result<(), Self::Error>;
71// }
72decl_threshold_traits!(
73    blocking,
74    RelativeHumidity,
75    RelativeHumiditySensor,
76    Percentage,
77    "percentage"
78);
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use crate::sensor::{Error, ErrorKind};
84    use assert_approx_eq::assert_approx_eq;
85
86    // Mock test value
87    const TEST_HUMIDITY: Percentage = 65.0;
88
89    #[derive(Debug)]
90    struct MockError;
91
92    impl Error for MockError {
93        fn kind(&self) -> ErrorKind {
94            ErrorKind::Other
95        }
96    }
97
98    struct MockHumiditySensor {
99        value: Percentage,
100        threshold_low: Option<Percentage>,
101        threshold_high: Option<Percentage>,
102        hysteresis: Option<Percentage>,
103    }
104
105    impl crate::sensor::ErrorType for MockHumiditySensor {
106        type Error = MockError;
107    }
108
109    impl RelativeHumiditySensor for MockHumiditySensor {
110        fn relative_humidity(&mut self) -> Result<Percentage, Self::Error> {
111            Ok(self.value)
112        }
113    }
114
115    impl RelativeHumidityThresholdSet for MockHumiditySensor {
116        fn set_relative_humidity_threshold_low(
117            &mut self,
118            threshold: Percentage,
119        ) -> Result<(), Self::Error> {
120            self.threshold_low = Some(threshold);
121            Ok(())
122        }
123
124        fn set_relative_humidity_threshold_high(
125            &mut self,
126            threshold: Percentage,
127        ) -> Result<(), Self::Error> {
128            self.threshold_high = Some(threshold);
129            Ok(())
130        }
131    }
132
133    impl RelativeHumidityHysteresis for MockHumiditySensor {
134        fn set_relative_humidity_threshold_hysteresis(
135            &mut self,
136            hysteresis: Percentage,
137        ) -> Result<(), Self::Error> {
138            self.hysteresis = Some(hysteresis);
139            Ok(())
140        }
141    }
142
143    #[test]
144    fn test_humidity_sensor_trait() {
145        let mut sensor = MockHumiditySensor {
146            value: TEST_HUMIDITY,
147            threshold_low: None,
148            threshold_high: None,
149            hysteresis: None,
150        };
151        let result = sensor.relative_humidity();
152        assert!(result.is_ok());
153        assert_approx_eq!(result.unwrap(), TEST_HUMIDITY);
154    }
155
156    #[test]
157    fn test_humidity_sensor_trait_mut_ref() {
158        let mut sensor = MockHumiditySensor {
159            value: TEST_HUMIDITY,
160            threshold_low: None,
161            threshold_high: None,
162            hysteresis: None,
163        };
164        let mut_ref = &mut sensor;
165        let result = mut_ref.relative_humidity();
166        assert!(result.is_ok());
167        let value = result.unwrap();
168        assert_approx_eq!(value, TEST_HUMIDITY);
169    }
170
171    #[test]
172    fn test_humidity_threshold_set_low() {
173        let mut sensor = MockHumiditySensor {
174            value: TEST_HUMIDITY,
175            threshold_low: None,
176            threshold_high: None,
177            hysteresis: None,
178        };
179        let threshold = 50.0;
180        let result = sensor.set_relative_humidity_threshold_low(threshold);
181        assert!(result.is_ok());
182        assert_approx_eq!(sensor.threshold_low.unwrap(), threshold);
183    }
184
185    #[test]
186    fn test_humidity_threshold_set_high() {
187        let mut sensor = MockHumiditySensor {
188            value: TEST_HUMIDITY,
189            threshold_low: None,
190            threshold_high: None,
191            hysteresis: None,
192        };
193        let threshold = 80.0;
194        let result = sensor.set_relative_humidity_threshold_high(threshold);
195        assert!(result.is_ok());
196        assert_approx_eq!(sensor.threshold_high.unwrap(), threshold);
197    }
198
199    #[test]
200    fn test_humidity_threshold_set_mut_ref() {
201        let mut sensor = MockHumiditySensor {
202            value: TEST_HUMIDITY,
203            threshold_low: None,
204            threshold_high: None,
205            hysteresis: None,
206        };
207        let mut_ref = &mut sensor;
208        let low_threshold = 40.0;
209        let high_threshold = 90.0;
210
211        let result_low = mut_ref.set_relative_humidity_threshold_low(low_threshold);
212        assert!(result_low.is_ok());
213
214        let result_high = mut_ref.set_relative_humidity_threshold_high(high_threshold);
215        assert!(result_high.is_ok());
216
217        assert_approx_eq!(sensor.threshold_low.unwrap(), low_threshold);
218        assert_approx_eq!(sensor.threshold_high.unwrap(), high_threshold);
219    }
220
221    #[test]
222    fn test_humidity_hysteresis() {
223        let mut sensor = MockHumiditySensor {
224            value: TEST_HUMIDITY,
225            threshold_low: None,
226            threshold_high: None,
227            hysteresis: None,
228        };
229        let hyst = 5.0;
230        let result = sensor.set_relative_humidity_threshold_hysteresis(hyst);
231        assert!(result.is_ok());
232        assert_approx_eq!(sensor.hysteresis.unwrap(), hyst);
233    }
234
235    #[test]
236    fn test_humidity_hysteresis_mut_ref() {
237        let mut sensor = MockHumiditySensor {
238            value: TEST_HUMIDITY,
239            threshold_low: None,
240            threshold_high: None,
241            hysteresis: None,
242        };
243        let mut_ref = &mut sensor;
244        let hyst = 3.0;
245        let result = mut_ref.set_relative_humidity_threshold_hysteresis(hyst);
246        assert!(result.is_ok());
247        assert_approx_eq!(sensor.hysteresis.unwrap(), hyst);
248    }
249}