Skip to main content

simple_dht11/
dht11.rs

1use rppal::gpio::{Gpio, IoPin, Mode};
2use std::thread::sleep;
3use std::time::Duration;
4
5pub struct Dht11 {
6    // The pin the DHT11 is connected to.
7    pin_number: u8,
8
9    // The IoPin used for communication with the DHT11
10    pin: Option<IoPin>,
11}
12
13pub struct Dht11Reading {
14    // The temperature in degrees Celsius
15    pub temperature: f32,
16
17    // The humidity in percent
18    pub humidity: f32,
19}
20
21impl Dht11 {
22    // Create a new DHT11 instance.
23    pub fn new(pin_number: u8) -> Dht11 {
24        let mut dht11 = Dht11 {
25            pin_number,
26            pin: None,
27        };
28
29        dht11.init_pin();
30
31        dht11
32    }
33
34    // Attempt to get a reading from the DHT11.
35    pub fn get_reading(&mut self) -> Dht11Reading {
36        let mut reading = self.read_data();
37
38        while reading.is_none() {
39            // Sleep for 500ms and try again
40            sleep(Duration::from_millis(500));
41
42            reading = self.read_data();
43        }
44
45        reading.unwrap()
46    }
47
48    // Initialize the pin
49    fn init_pin(&mut self) {
50        // Initialize the pin.
51        self.pin = Some(
52            Gpio::new()
53                .unwrap()
54                .get(self.pin_number)
55                .unwrap()
56                .into_io(Mode::Output),
57        );
58    }
59
60    // Read the temperature and humidity from the DHT11.
61    fn read_data(&mut self) -> Option<Dht11Reading> {
62        // The data bytes length received from the DHT11.
63        const DATA_LENGTH: u8 = 40;
64        let mut data: [u8; DATA_LENGTH as usize] = [0; DATA_LENGTH as usize];
65        let mut has_received_response = false;
66        let mut data_response_counter: u8 = 0;
67
68        self.send_start_signal();
69
70        self.pin.as_mut().unwrap().set_mode(Mode::Input);
71
72        if let Some(pin) = &self.pin {
73            while data_response_counter < DATA_LENGTH {
74                let start_time = std::time::Instant::now();
75                while pin.is_low() {
76                    // wait for pin to go high
77                    // if its > 100ms, then we return
78                    if start_time.elapsed().as_millis() > 100 {
79                        return None;
80                    }
81                }
82
83                let set_high_time = std::time::Instant::now();
84
85                while pin.is_high() {
86                    // wait for pin to go low
87                    // if its > 100ms, then we return
88                    if set_high_time.elapsed().as_millis() > 100 {
89                        return None;
90                    }
91                }
92
93                let set_low_time = std::time::Instant::now();
94
95                let duration = set_low_time.duration_since(set_high_time);
96
97                if !has_received_response {
98                    has_received_response = true;
99                    // We skip the first reading, because it is the response from the DHT11.
100                    continue;
101                }
102
103                if duration < Duration::from_micros(80) {
104                    if duration > Duration::from_micros(30) {
105                        data[data_response_counter as usize] = 1;
106                    } else {
107                        data[data_response_counter as usize] = 0;
108                    }
109
110                    data_response_counter += 1;
111                }
112            }
113        }
114
115        let mut humidity_int: u8 = 0;
116        let mut humidity_dec: u8 = 0;
117        let mut temperature_int: u8 = 0;
118        let mut temperature_dec: u8 = 0;
119
120        for i in 0..8 {
121            humidity_int += data[i] << (7 - i);
122        }
123
124        for i in 0..8 {
125            humidity_dec += data[i + 8] << (7 - i);
126        }
127
128        for i in 0..8 {
129            temperature_int += data[i + 16] << (7 - i);
130        }
131
132        for i in 0..8 {
133            temperature_dec += data[i + 24] << (7 - i);
134        }
135
136        let humidity = humidity_int as f32 + humidity_dec as f32 / 10.0;
137        let temperature = temperature_int as f32 + temperature_dec as f32 / 10.0;
138
139        Some(Dht11Reading {
140            temperature,
141            humidity,
142        })
143    }
144
145    fn send_start_signal(&mut self) {
146        self.pin.as_mut().unwrap().set_mode(Mode::Output);
147
148        // Set the pin to high
149        self.pin.as_mut().unwrap().set_high();
150
151        // Wait for 30ms
152        sleep(Duration::from_millis(30));
153
154        // Set the pin to low
155        self.pin.as_mut().unwrap().set_low();
156
157        // Wait for 20ms
158        sleep(Duration::from_millis(20));
159
160        // Set the pin to high
161        self.pin.as_mut().unwrap().set_high();
162
163        // Wait for 40us
164        sleep(Duration::from_micros(40));
165    }
166}