1#![cfg_attr(not(test), no_std)]
35
36mod read;
37use embedded_hal::delay::DelayNs;
38use embedded_hal::digital::{InputPin, OutputPin};
39pub use read::DhtError;
40
41pub mod dht11 {
42 use super::*;
43
44 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
45 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
46 pub struct Reading {
47 pub temperature: i8,
48 pub relative_humidity: u8,
49 }
50
51 pub mod blocking {
52 use super::DelayNs;
53 use super::{raw_to_reading, InputPin, OutputPin, Reading};
54
55 pub fn read<P: OutputPin + InputPin>(
56 delay: &mut impl DelayNs,
57 pin: &mut P,
58 ) -> Result<Reading, super::read::DhtError<P::Error>> {
59 pin.set_low()?;
60 delay.delay_ms(18);
61 super::read::read_raw(delay, pin).map(raw_to_reading)
62 }
63 }
64
65 #[cfg(feature = "async")]
66 pub mod r#async {
67 use super::DelayNs;
68 use super::{raw_to_reading, InputPin, OutputPin, Reading};
69 use embedded_hal_async::delay::DelayNs as AsyncDelayNs;
70
71 pub async fn read<P: OutputPin + InputPin>(
75 delay: &mut (impl AsyncDelayNs + DelayNs),
76 pin: &mut P,
77 ) -> Result<Reading, crate::read::DhtError<P::Error>> {
78 pin.set_low()?;
79 embedded_hal_async::delay::DelayNs::delay_ms(delay, 18).await;
80 crate::read::read_raw(delay, pin).map(raw_to_reading)
81 }
82 }
83
84 fn raw_to_reading(bytes: [u8; 4]) -> Reading {
85 let [relative_humidity, _, temp_signed, _] = bytes;
86 let temperature = {
87 let (signed, magnitude) = convert_signed(temp_signed);
88 let temp_sign = if signed { -1 } else { 1 };
89 temp_sign * magnitude as i8
90 };
91 Reading {
92 temperature,
93 relative_humidity,
94 }
95 }
96
97 #[test]
98 fn test_raw_to_reading() {
99 assert_eq!(
100 raw_to_reading([0x32, 0, 0x1B, 0]),
101 Reading {
102 temperature: 27,
103 relative_humidity: 50
104 }
105 );
106 assert_eq!(
107 raw_to_reading([0x80, 0, 0x83, 0]),
108 Reading {
109 temperature: -3,
110 relative_humidity: 128
111 }
112 );
113 }
114}
115
116pub mod dht22 {
117 use super::*;
118
119 #[derive(Clone, Copy, Debug, PartialEq)]
120 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
121 pub struct Reading {
122 pub temperature: f32,
123 pub relative_humidity: f32,
124 }
125
126 pub mod blocking {
127 use super::DelayNs;
128 use super::{raw_to_reading, InputPin, OutputPin, Reading};
129 pub fn read<P: OutputPin + InputPin>(
130 delay: &mut impl DelayNs,
131 pin: &mut P,
132 ) -> Result<Reading, super::read::DhtError<P::Error>> {
133 pin.set_low()?;
134 delay.delay_ms(1);
135 super::read::read_raw(delay, pin).map(raw_to_reading)
136 }
137 }
138
139 #[cfg(feature = "async")]
140 pub mod r#async {
141 use super::DelayNs;
142 use super::{raw_to_reading, InputPin, OutputPin, Reading};
143 use embedded_hal_async::delay::DelayNs as AsyncDelayNs;
144
145 pub async fn read<P: OutputPin + InputPin>(
149 delay: &mut (impl AsyncDelayNs + DelayNs),
150 pin: &mut P,
151 ) -> Result<Reading, crate::read::DhtError<P::Error>> {
152 pin.set_low()?;
153 embedded_hal_async::delay::DelayNs::delay_ms(delay, 1).await;
154 crate::read::read_raw(delay, pin).map(raw_to_reading)
155 }
156 }
157
158 fn raw_to_reading(bytes: [u8; 4]) -> Reading {
159 let [rh_h, rh_l, temp_h_signed, temp_l] = bytes;
160 let relative_humidity = ((rh_h as u16) << 8 | (rh_l as u16)) as f32 / 10.0;
161 let temperature = {
162 let (signed, magnitude) = convert_signed(temp_h_signed);
163 let temp_sign = if signed { -1.0 } else { 1.0 };
164 let temp_magnitude = ((magnitude as u16) << 8) | temp_l as u16;
165 temp_sign * temp_magnitude as f32 / 10.0
166 };
167 Reading {
168 temperature,
169 relative_humidity,
170 }
171 }
172
173 #[test]
174 fn test_raw_to_reading() {
175 assert_eq!(
176 raw_to_reading([0x02, 0x10, 0x01, 0x1B]),
177 Reading {
178 temperature: 28.3,
179 relative_humidity: 52.8
180 }
181 );
182 assert_eq!(
183 raw_to_reading([0x02, 0x90, 0x80, 0x1B]),
184 Reading {
185 temperature: -2.7,
186 relative_humidity: 65.6
187 }
188 );
189 }
190}
191
192fn convert_signed(signed: u8) -> (bool, u8) {
193 let sign = signed & 0x80 != 0;
194 let magnitude = signed & 0x7F;
195 (sign, magnitude)
196}
197
198#[test]
199fn test_convert_signed() {
200 assert_eq!(convert_signed(0x13), (false, 0x13));
201 assert_eq!(convert_signed(0x93), (true, 0x13));
202}