truebner_smt100/
lib.rs

1#[cfg(any(feature = "modbus-rtu"))]
2pub mod modbus;
3
4#[cfg(any(feature = "mock"))]
5pub mod mock;
6
7use futures::Future;
8use std::{fmt, io::Error, time::Duration};
9
10/// (Thermodynamic) Temperature.
11#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
12#[repr(transparent)]
13pub struct Temperature(f64);
14
15impl Temperature {
16    pub const fn from_degree_celsius(degree_celsius: f64) -> Self {
17        Self(degree_celsius)
18    }
19
20    pub const fn to_degree_celsius(self) -> f64 {
21        self.0
22    }
23}
24
25impl From<f64> for Temperature {
26    fn from(from: f64) -> Self {
27        Temperature(from)
28    }
29}
30
31impl From<Temperature> for f64 {
32    fn from(from: Temperature) -> Self {
33        from.0
34    }
35}
36
37impl fmt::Display for Temperature {
38    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39        write!(f, "{} °C", self.to_degree_celsius())
40    }
41}
42
43/// Volumetric water content (VWC).
44#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
45#[repr(transparent)]
46pub struct VolumetricWaterContent(f64);
47
48impl VolumetricWaterContent {
49    pub const fn from_percent(percent: f64) -> Self {
50        Self(percent)
51    }
52
53    pub const fn to_percent(self) -> f64 {
54        self.0
55    }
56
57    pub const fn min_percent() -> f64 {
58        0.0
59    }
60
61    pub const fn max_percent() -> f64 {
62        100.0
63    }
64
65    pub const fn min() -> Self {
66        Self::from_percent(Self::min_percent())
67    }
68
69    pub const fn max() -> Self {
70        Self::from_percent(Self::max_percent())
71    }
72
73    pub fn is_valid(self) -> bool {
74        self >= Self::min() && self <= Self::max()
75    }
76}
77
78impl fmt::Display for VolumetricWaterContent {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        write!(f, "{} %", self.to_percent())
81    }
82}
83
84/// Relative permittivity or dielectric constant (DK).
85#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
86#[repr(transparent)]
87pub struct RelativePermittivity(f64);
88
89impl RelativePermittivity {
90    pub const fn from_ratio(percent: f64) -> Self {
91        Self(percent)
92    }
93
94    pub const fn to_ratio(self) -> f64 {
95        self.0
96    }
97
98    pub const fn min_ratio() -> f64 {
99        1.0
100    }
101
102    pub const fn min() -> Self {
103        Self::from_ratio(Self::min_ratio())
104    }
105
106    pub fn is_valid(self) -> bool {
107        self >= Self::min()
108    }
109}
110
111impl fmt::Display for RelativePermittivity {
112    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113        write!(f, "{}", self.to_ratio())
114    }
115}
116
117/// Asynchronous interface that exposes the generic capabilities of the
118/// TRUEBNER SMT100 Soil Moisture Sensor.
119pub trait Capabilities {
120    /// Measure the current temperature in the range from -40°C to +80°C
121    /// (analog version from -40°C to +60°C).
122    fn read_temperature(&self, timeout: Duration)
123        -> Box<dyn Future<Item = Temperature, Error = Error>>;
124
125    /// Measure the current water content of the medium (soil) around the sensor
126    /// in the range from 0% to 60% (up to 100% with limited accuracy).
127    fn read_water_content(
128        &self,
129        timeout: Duration,
130    ) -> Box<dyn Future<Item = VolumetricWaterContent, Error = Error>>;
131
132    /// Measure the current (relative) permittivity of the medium around the sensor.
133    fn read_permittivity(
134        &self,
135        timeout: Duration,
136    ) -> Box<dyn Future<Item = RelativePermittivity, Error = Error>>;
137
138    /// Retrieve the current raw and uncalibrated signal of the sensor.
139    fn read_raw_counts(&self, timeout: Duration) -> Box<dyn Future<Item = usize, Error = Error>>;
140}
141
142#[cfg(test)]
143mod tests {
144    use super::*;
145
146    #[test]
147    fn water_content_percent() {
148        for i in 0..=100 {
149            let vwc = VolumetricWaterContent::from_percent(i as f64);
150            assert!(vwc.is_valid());
151            assert_eq!(vwc.to_percent(), i as f64);
152        }
153        assert!(!VolumetricWaterContent::from_percent(-0.5).is_valid());
154        assert!(!VolumetricWaterContent::from_percent(100.01).is_valid());
155    }
156}