Data Parser
The parse_data function takes the raw data bytes from the sensor and converts them into meaningful temperature and humidity values. The DHT22 sends two bytes for humidity and two for temperature.
#![allow(unused)]
fn main() {
fn parse_data(&self, data: [u8; 4]) -> Reading {
let [hum_hi, hum_lo, temp_hi, temp_lo] = data;
let joined_humidity = u16::from_be_bytes([hum_hi, hum_lo]);
let relative_humidity = joined_humidity as f32 / 10.0;
let is_temp_negative = (temp_hi >> 7) != 0;
let temp_hi = temp_hi & 0b0111_1111;
let joined_temp = u16::from_be_bytes([temp_hi, temp_lo]);
let mut temperature = joined_temp as f32 / 10.0;
if is_temp_negative {
temperature = -temperature;
}
Reading {
temperature,
relative_humidity,
}
}
}
Decode Humidity
The humidity is received as two bytes: hum_hi and hum_lo. These two bytes together form a 16-bit number. We join them using:
#![allow(unused)]
fn main() {
let joined_humidity = u16::from_be_bytes([hum_hi, hum_lo]);
}
The actual humidity is this value divided by 10.0:
#![allow(unused)]
fn main() {
let relative_humidity = joined_humidity as f32 / 10.0;
}
For example, if the sensor sends 0x02 and 0x58 (which is 600 in decimal), the humidity will be 600 / 10 = 60.0%.
Decode Temperature
The temperature is also received as two bytes: temp_hi and temp_lo.
However, the sensor uses the highest bit of “temp_hi” to indicate if the temperature is negative. So first, we check if that bit is set:
#![allow(unused)]
fn main() {
let is_temp_negative = (temp_hi >> 7) != 0;
}
We then clear the sign bit (bit 7) before combining the bytes:
#![allow(unused)]
fn main() {
let temp_hi = temp_hi & 0b0111_1111;
let joined_temp = u16::from_be_bytes([temp_hi, temp_lo]);
let mut temperature = joined_temp as f32 / 10.0;
}
If the temperature was marked as negative, we flip the sign:
#![allow(unused)]
fn main() {
if is_temp_negative {
temperature = -temperature;
}
}
Finally, we return the result:
#![allow(unused)]
fn main() {
Reading {
temperature,
relative_humidity,
}
}
Testing parser
There is nothing complex going on in these tests. We are simply checking if the parse_data function correctly converts raw bytes into meaningful temperature and humidity values.
In the first test, we pass a sample input representing 55.5% humidity and 24.6°C temperature and assert that the output matches.
In the second test, we use a special case where the temperature is negative (-1.0°C). The most significant bit (bit 7) in the temperature high byte is set, which signals a negative temperature.
#![allow(unused)]
fn main() {
#[test]
fn test_parse_data_positive_temp() {
let mut pin = PinMock::new(&[]);
let dht = Dht22::new(pin.clone(), NoopDelay);
// Humidity: 55.5% -> [0x02, 0x2B] => 555
// Temperature: 24.6C -> [0x00, 0xF6] => 246
let data = [0x02, 0x2B, 0x00, 0xF6];
let reading = dht.parse_data(data);
assert_eq!(
reading,
Reading {
relative_humidity: 55.5,
temperature: 24.6,
}
);
pin.done();
}
#[test]
fn test_parse_data_negative_temp() {
let mut pin = PinMock::new(&[]);
let dht = Dht22::new(pin.clone(), NoopDelay);
// Humidity: 40.0% -> [0x01, 0x90] => 400
// Temperature: -1.0C -> [0x80, 0x0A]
// Bit 7 of temp_hi is 1 => negative
// Clear sign bit: 0x80 & 0x7F = 0x00, so [0x00, 0x0A] = 10 => 1.0 then negated
let data = [0x01, 0x90, 0x80, 0x0A];
let reading = dht.parse_data(data);
assert_eq!(
reading,
Reading {
relative_humidity: 40.0,
temperature: -1.0,
}
);
pin.done();
}
}