1use rppal::gpio::{Gpio, IoPin, Mode};
2use std::thread::sleep;
3use std::time::Duration;
4
5pub struct Dht11 {
6 pin_number: u8,
8
9 pin: Option<IoPin>,
11}
12
13pub struct Dht11Reading {
14 pub temperature: f32,
16
17 pub humidity: f32,
19}
20
21impl Dht11 {
22 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 pub fn get_reading(&mut self) -> Dht11Reading {
36 let mut reading = self.read_data();
37
38 while reading.is_none() {
39 sleep(Duration::from_millis(500));
41
42 reading = self.read_data();
43 }
44
45 reading.unwrap()
46 }
47
48 fn init_pin(&mut self) {
50 self.pin = Some(
52 Gpio::new()
53 .unwrap()
54 .get(self.pin_number)
55 .unwrap()
56 .into_io(Mode::Output),
57 );
58 }
59
60 fn read_data(&mut self) -> Option<Dht11Reading> {
62 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 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 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 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 self.pin.as_mut().unwrap().set_high();
150
151 sleep(Duration::from_millis(30));
153
154 self.pin.as_mut().unwrap().set_low();
156
157 sleep(Duration::from_millis(20));
159
160 self.pin.as_mut().unwrap().set_high();
162
163 sleep(Duration::from_micros(40));
165 }
166}