Adding DHT22/AM2302 sensor libraries (Arduino and PietteTech) but using Arduino for...
[iotcloud.git] / version2 / src / others / PietteTech_DHT / PietteTech_DHT.cpp
1 /*
2  * FILE:        PietteTech_DHT.cpp
3  * VERSION:     0.3
4  * PURPOSE:     Spark Interrupt driven lib for DHT sensors
5  * LICENSE:     GPL v3 (http://www.gnu.org/licenses/gpl.html)
6  *
7  * S Piette (Piette Technologies) scott.piette@gmail.com
8  *      January 2014        Original Spark Port
9  *      October 2014        Added support for DHT21/22 sensors
10  *                          Improved timing, moved FP math out of ISR
11  *
12  * Based on adaptation by niesteszeck (github/niesteszeck)
13  * Based on original DHT11 library (http://playgroudn.adruino.cc/Main/DHT11Lib)
14  *
15  *
16  * This library supports the DHT sensor on the following pins
17  * D0, D1, D2, D3, D4, A0, A1, A3, A5, A6, A7
18  * http://docs.spark.io/firmware/#interrupts-attachinterrupt
19  *
20  */
21
22 /*
23     Timing of DHT22 SDA signal line after MCU pulls low for 1ms
24     https://github.com/mtnscott/Spark_DHT/AM2302.pdf
25
26   - - - -            -----           -- - - --            ------- - -
27          \          /     \         /  \      \          /
28           +        /       +       /    +      +        /
29            \      /         \     /      \      \      /
30             ------           -----        -- - --------
31  ^        ^                ^                   ^          ^
32  |   Ts   |        Tr      |        Td         |    Te    |
33
34     Ts : Start time from MCU changing SDA from Output High to Tri-State (Hi-Z)
35          Spec: 20-200us             Tested: < 65us
36     Tr : DHT response to MCU controlling SDA and pulling Low and High to
37          start of first data bit
38          Spec: 150-170us            Tested: 125 - 200us
39     Td : DHT data bit, falling edge to falling edge
40          Spec: '0' 70us - 85us      Tested: 60 - 110us
41          Spec: '1' 116us - 130us    Tested: 111 - 155us
42     Te : DHT releases SDA to Tri-State (Hi-Z)
43          Spec: 45-55us              Not Tested
44  */
45
46 #include "application.h"
47 #include "math.h"
48 #include "PietteTech_DHT.h"
49
50 // Thanks to Paul Kourany for this word type conversion function
51 uint16_t word(uint8_t high, uint8_t low) {
52     uint16_t ret_val = low;
53     ret_val += (high << 8);
54     return ret_val;
55 }
56
57 PietteTech_DHT::PietteTech_DHT(uint8_t sigPin, uint8_t dht_type, void (*callback_wrapper)()) {
58     begin(sigPin, dht_type, callback_wrapper);
59     _firstreading = true;
60 }
61
62 void PietteTech_DHT::begin(uint8_t sigPin, uint8_t dht_type, void (*callback_wrapper) ()) {
63     _sigPin = sigPin;
64     _type = dht_type;
65     isrCallback_wrapper = callback_wrapper;
66
67     pinMode(sigPin, OUTPUT);
68     digitalWrite(sigPin, HIGH);
69     _lastreadtime = 0;
70     _state = STOPPED;
71     _status = DHTLIB_ERROR_NOTSTARTED;
72 }
73
74 int PietteTech_DHT::acquire() {
75     // Check if sensor was read less than two seconds ago and return early
76     // to use last reading
77     unsigned long currenttime = millis();
78     if (currenttime < _lastreadtime) {
79         // there was a rollover
80         _lastreadtime = 0;
81     }
82     if (!_firstreading && ((currenttime - _lastreadtime) < 2000 )) {
83         // return last correct measurement, (this read time - last read time) < device limit
84         return DHTLIB_ACQUIRED;
85     }
86
87     if (_state == STOPPED || _state == ACQUIRED) {
88         /*
89          * Setup the initial state machine
90          */
91         _firstreading = false;
92         _lastreadtime = currenttime;
93         _state = RESPONSE;
94
95 #if defined(DHT_DEBUG_TIMING)
96         /*
97          * Clear the debug timings array
98          */
99         for (int i = 0; i < 41; i++) _edges[i] = 0;
100         _e = &_edges[0];
101 #endif
102
103         /*
104          * Set the initial values in the buffer and variables
105          */
106         for (int i = 0; i < 5; i++) _bits[i] = 0;
107         _cnt = 7;
108         _idx = 0;
109         _hum = 0;
110         _temp = 0;
111
112         /*
113          * Toggle the digital output to trigger the DHT device
114          * to send us temperature and humidity data
115          */
116         pinMode(_sigPin, OUTPUT);
117         digitalWrite(_sigPin, LOW);
118         if (_type == DHT11)
119             delay(18);                  // DHT11 Spec: 18ms min
120         else
121             delayMicroseconds(1500);    // DHT22 Spec: 0.8-20ms, 1ms typ
122         pinMode(_sigPin, INPUT);        // Note Hi-Z mode with pullup resistor
123                                         // will keep this high until the DHT responds.
124         /*
125          * Attach the interrupt handler to receive the data once the DHT
126          * starts to send us data
127          */
128         _us = micros();
129         attachInterrupt(_sigPin, isrCallback_wrapper, FALLING);
130
131         return DHTLIB_ACQUIRING;
132     } else
133         return DHTLIB_ERROR_ACQUIRING;
134 }
135
136 int PietteTech_DHT::acquireAndWait() {
137     acquire();
138     while(acquiring()) ;
139     return getStatus();
140 }
141
142 void PietteTech_DHT::isrCallback() {
143     unsigned long newUs = micros();
144     unsigned long delta = (newUs - _us);
145     _us = newUs;
146
147     if (delta > 6000) {
148         _status = DHTLIB_ERROR_ISR_TIMEOUT;
149         _state = STOPPED;
150         detachInterrupt(_sigPin);
151         return;
152     }
153     switch(_state) {
154         case RESPONSE:            // Spec: 80us LOW followed by 80us HIGH
155             if(delta < 65) {      // Spec: 20-200us to first falling edge of response
156                 _us -= delta;
157                 break; //do nothing, it started the response signal
158             } if(125 < delta && delta < 200) {
159 #if defined(DHT_DEBUG_TIMING)
160                 *_e++ = delta;  // record the edge -> edge time
161 #endif
162                 _state = DATA;
163             } else {
164                 detachInterrupt(_sigPin);
165                 _status = DHTLIB_ERROR_RESPONSE_TIMEOUT;
166                 _state = STOPPED;
167 #if defined(DHT_DEBUG_TIMING)
168                 *_e++ = delta;  // record the edge -> edge time
169 #endif
170             }
171             break;
172         case DATA:          // Spec: 50us low followed by high of 26-28us = 0, 70us = 1
173             if(60 < delta && delta < 155) { //valid in timing
174                 _bits[_idx] <<= 1; // shift the data
175                 if(delta > 110) //is a one
176                     _bits[_idx] |= 1;
177 #if defined(DHT_DEBUG_TIMING)
178                 *_e++ = delta;  // record the edge -> edge time
179 #endif
180                 if (_cnt == 0) { // we have completed the byte, go to next
181                     _cnt = 7; // restart at MSB
182                     if(++_idx == 5) { // go to next byte, if we have got 5 bytes stop.
183                         detachInterrupt(_sigPin);
184                         // Verify checksum
185                         uint8_t sum = _bits[0] + _bits[1] + _bits[2] + _bits[3];
186                         if (_bits[4] != sum) {
187                             _status = DHTLIB_ERROR_CHECKSUM;
188                             _state = STOPPED;
189                         } else {
190                             _status = DHTLIB_OK;
191                             _state = ACQUIRED;
192                             _convert = true;
193                         }
194                         break;
195                     }
196                 } else _cnt--;
197             } else if(delta < 10) {
198                 detachInterrupt(_sigPin);
199                 _status = DHTLIB_ERROR_DELTA;
200                 _state = STOPPED;
201             } else {
202                 detachInterrupt(_sigPin);
203                 _status = DHTLIB_ERROR_DATA_TIMEOUT;
204                 _state = STOPPED;
205             }
206             break;
207         default:
208             break;
209     }
210 }
211
212 void PietteTech_DHT::convert() {
213     // Calculate the temperature and humidity based on the sensor type
214     switch (_type) {
215         case DHT11:
216             _hum = _bits[0];
217             _temp = _bits[2];
218             break;
219         case DHT22:
220         case DHT21:
221             _hum = word(_bits[0], _bits[1]) * 0.1;
222             _temp = (_bits[2] & 0x80 ?
223                      -word(_bits[2] & 0x7F, _bits[3]) :
224                      word(_bits[2], _bits[3])) * 0.1;
225             break;
226     }
227     _convert = false;
228 }
229
230 bool PietteTech_DHT::acquiring() {
231     if (_state != ACQUIRED && _state != STOPPED)
232         return true;
233     return false;
234 }
235
236 int PietteTech_DHT::getStatus() {
237     return _status;
238 }
239
240 float PietteTech_DHT::getCelsius() {
241     DHT_CHECK_STATE;
242     return _temp;
243 }
244
245 float PietteTech_DHT::getHumidity() {
246     DHT_CHECK_STATE;
247     return _hum;
248 }
249
250 float PietteTech_DHT::getFahrenheit() {
251     DHT_CHECK_STATE;
252     return _temp * 9 / 5 + 32;
253 }
254
255 float PietteTech_DHT::getKelvin() {
256     DHT_CHECK_STATE;
257     return _temp + 273.15;
258 }
259
260 /*
261  * Added methods for supporting Adafruit Unified Sensor framework
262  */
263 float PietteTech_DHT::readTemperature() {
264     acquireAndWait();
265     return getCelsius();
266 }
267
268 float PietteTech_DHT::readHumidity() {
269     acquireAndWait();
270     return getHumidity();
271 }
272
273 // delta max = 0.6544 wrt dewPoint()
274 // 5x faster than dewPoint()
275 // reference: http://en.wikipedia.org/wiki/Dew_point
276 double PietteTech_DHT::getDewPoint() {
277     DHT_CHECK_STATE;
278     double a = 17.271;
279     double b = 237.7;
280     double temp_ = (a * (double) _temp) / (b + (double) _temp) + log( (double) _hum/100);
281     double Td = (b * temp_) / (a - temp_);
282     return Td;
283 }
284
285 // dewPoint function NOAA
286 // reference: http://wahiduddin.net/calc/density_algorithms.htm
287 double PietteTech_DHT::getDewPointSlow() {
288     DHT_CHECK_STATE;
289     double a0 = (double) 373.15 / (273.15 + (double) _temp);
290     double SUM = (double) -7.90298 * (a0-1.0);
291     SUM += 5.02808 * log10(a0);
292     SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/a0)))-1) ;
293     SUM += 8.1328e-3 * (pow(10,(-3.49149*(a0-1)))-1) ;
294     SUM += log10(1013.246);
295     double VP = pow(10, SUM-3) * (double) _hum;
296     double T = log(VP/0.61078); // temp var
297     return (241.88 * T) / (17.558-T);
298 }