#![cfg_attr(not(test), no_std)]
mod read;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
pub use read::DhtError;
pub mod dht11 {
use super::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Reading {
pub temperature: i8,
pub relative_humidity: u8,
}
pub mod blocking {
use super::DelayNs;
use super::{raw_to_reading, InputPin, OutputPin, Reading};
pub fn read<P: OutputPin + InputPin>(
delay: &mut impl DelayNs,
pin: &mut P,
) -> Result<Reading, super::read::DhtError<P::Error>> {
pin.set_low()?;
delay.delay_ms(18);
super::read::read_raw(delay, pin).map(raw_to_reading)
}
}
#[cfg(feature = "async")]
pub mod r#async {
use super::DelayNs;
use super::{raw_to_reading, InputPin, OutputPin, Reading};
use embedded_hal_async::delay::DelayNs as AsyncDelayNs;
pub async fn read<P: OutputPin + InputPin>(
delay: &mut (impl AsyncDelayNs + DelayNs),
pin: &mut P,
) -> Result<Reading, crate::read::DhtError<P::Error>> {
pin.set_low()?;
embedded_hal_async::delay::DelayNs::delay_ms(delay, 18).await;
crate::read::read_raw(delay, pin).map(raw_to_reading)
}
}
fn raw_to_reading(bytes: [u8; 4]) -> Reading {
let [relative_humidity, _, temp_signed, _] = bytes;
let temperature = {
let (signed, magnitude) = convert_signed(temp_signed);
let temp_sign = if signed { -1 } else { 1 };
temp_sign * magnitude as i8
};
Reading {
temperature,
relative_humidity,
}
}
#[test]
fn test_raw_to_reading() {
assert_eq!(
raw_to_reading([0x32, 0, 0x1B, 0]),
Reading {
temperature: 27,
relative_humidity: 50
}
);
assert_eq!(
raw_to_reading([0x80, 0, 0x83, 0]),
Reading {
temperature: -3,
relative_humidity: 128
}
);
}
}
pub mod dht22 {
use super::*;
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Reading {
pub temperature: f32,
pub relative_humidity: f32,
}
pub mod blocking {
use super::DelayNs;
use super::{raw_to_reading, InputPin, OutputPin, Reading};
pub fn read<P: OutputPin + InputPin>(
delay: &mut impl DelayNs,
pin: &mut P,
) -> Result<Reading, super::read::DhtError<P::Error>> {
pin.set_low()?;
delay.delay_ms(1);
super::read::read_raw(delay, pin).map(raw_to_reading)
}
}
#[cfg(feature = "async")]
pub mod r#async {
use super::DelayNs;
use super::{raw_to_reading, InputPin, OutputPin, Reading};
use embedded_hal_async::delay::DelayNs as AsyncDelayNs;
pub async fn read<P: OutputPin + InputPin>(
delay: &mut (impl AsyncDelayNs + DelayNs),
pin: &mut P,
) -> Result<Reading, crate::read::DhtError<P::Error>> {
pin.set_low()?;
embedded_hal_async::delay::DelayNs::delay_ms(delay, 1).await;
crate::read::read_raw(delay, pin).map(raw_to_reading)
}
}
fn raw_to_reading(bytes: [u8; 4]) -> Reading {
let [rh_h, rh_l, temp_h_signed, temp_l] = bytes;
let relative_humidity = ((rh_h as u16) << 8 | (rh_l as u16)) as f32 / 10.0;
let temperature = {
let (signed, magnitude) = convert_signed(temp_h_signed);
let temp_sign = if signed { -1.0 } else { 1.0 };
let temp_magnitude = ((magnitude as u16) << 8) | temp_l as u16;
temp_sign * temp_magnitude as f32 / 10.0
};
Reading {
temperature,
relative_humidity,
}
}
#[test]
fn test_raw_to_reading() {
assert_eq!(
raw_to_reading([0x02, 0x10, 0x01, 0x1B]),
Reading {
temperature: 28.3,
relative_humidity: 52.8
}
);
assert_eq!(
raw_to_reading([0x02, 0x90, 0x80, 0x1B]),
Reading {
temperature: -2.7,
relative_humidity: 65.6
}
);
}
}
fn convert_signed(signed: u8) -> (bool, u8) {
let sign = signed & 0x80 != 0;
let magnitude = signed & 0x7F;
(sign, magnitude)
}
#[test]
fn test_convert_signed() {
assert_eq!(convert_signed(0x13), (false, 0x13));
assert_eq!(convert_signed(0x93), (true, 0x13));
}