-
Notifications
You must be signed in to change notification settings - Fork 126
/
Copy pathdht11.js
217 lines (194 loc) · 6.47 KB
/
dht11.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
var rpio = require('../lib/rpio');
/*
* Repeatedly read a DHT11 attached to Pin 7 / GPIO 4 and print out the current
* temperature and relative humidity if the read was successful.
*/
var pin = 7;
/*
* Print debug messages if enabled.
*/
var debug = false;
function dbg()
{
if (debug) {
console.error.apply(console, arguments);
}
}
/*
* The DHT11 transmission is made up of 40 "bits", where the length of each
* high output determines whether it is a 0 or 1. Per the datasheet, "0" is
* 26-28us in length, and "1" 70us. However, in a JS environment we can't be
* so precise, and so we determine what is high and low based on a sampling of
* the values we received.
*
* These devices are notoriously unreliable, so this program will run forever
* attempting to retrieve and print valid data until the user kills the process.
*
* For the most portable implementation we read all bits after initialisation
* into a big buffer as fast as possible, and then parse afterwards. This is
* necessary on e.g. the original Raspberry Pi 1 as the CPU is not fast enough
* to do something like:
*
* while ((curstate = rpio.read(...)) == laststate)
* count++;
*
* for each read, which would be the normal way of doing something like this.
*/
function read_dht11(vals)
{
/*
* Our read buffer of all the bits sent. Should be plenty. On a
* Raspberry Pi 4 a successful read uses up about half of this.
*/
var buf = new Buffer(50000);
/*
* Array storing the data bits received from the DHT11 after parsing
* the input buffer.
*/
var data = new Array();
/*
* The initialisation sequence as per the datasheet is to start high,
* pull low for at least 18ms, then back high and read. The JavaScript
* function call overhead ensures that we'll actually be sleeping
* longer than that, but it doesn't appear to be a problem.
*/
rpio.open(pin, rpio.OUTPUT, rpio.HIGH);
rpio.write(pin, rpio.LOW);
rpio.msleep(18);
/*
* Enable the pin pull-up then use the mode-setting variant of readbuf()
* to read the pin value into the buffer as fast as possible. We only
* have around 100us before the DHT11 will start transmitting data so
* there needs to be no delay between configuring the pin as an input and
* reading the data.
*
* Configuring the pin for input, enabling the pull-up, then reading the
* data would take way too long. Apart from the JavaScript function call
* overhead, just enabling the pull-up can require a 150us delay on some
* hardware.
*/
rpio.pud(pin, rpio.PULL_UP);
rpio.readbuf(pin, buf, buf.length, true);
rpio.close(pin);
/*
* The data has been received, split the buffer into groups of "1"s. By
* measuring the length of each group we can determine whether it is a
* low (short) or high (long) bit sent by the DHT11.
*/
buf.join('').replace(/0+/g, '0').split('0').forEach(function(bits, n) {
data.push(bits.length);
});
/*
* In normal operation we'd expect to see 43 values: the initial high of
* the pull-up, a ready signal, 40 bits of data, then a continuous high
* to signal end of transmission. Use shift() and pop() to remove the
* control bits, leaving just the data.
*
* In certain circumstances the first bit can be missing, if we didn't
* switch to read mode fast enough. However as that's just the high
* value configured by the pull-up and not data from the DHT11 we allow
* it to be missing. Everything else, even with a correct checksum (can
* happen!) we treat as invalid.
*/
if (data.length < 42 || data.length > 43) {
dbg("Bad data read: length=%d", data.length);
return false;
}
/* Remove extra first bit generated by the pull-up */
if (data.length == 43) {
data.shift();
}
/* Remove data ready bit */
data.shift();
/* Remove end of transmission bit */
data.pop();
/*
* Calculate the low and high water marks. As each model of Raspberry
* Pi will run at different speeds, the length of each high bit will
* vary, so calculate the average and use that to determine what is
* "high" and "low".
*
* The longest "low" seen on a Raspberry Pi 4 is around 135, so the
* default low here should be more than sufficient.
*/
var low = 10000;
var high = 0;
for (var i = 0; i < data.length; i++) {
if (data[i] < low)
low = data[i];
if (data[i] > high)
high = data[i];
}
var avg = (low + high) / 2;
/*
* The data received from the DHT11 is in 5 groups of 8-bits:
*
* [0:7] integral relative humidity
* [8:15] decimal relative humidity
* [16:23] integral temperature
* [24:31] decimal temperature
* [32:39] checksum
*
* Parse the bitstream into the supplied "vals" buffer.
*/
vals.fill(0);
for (var i = 0; i < data.length; i++) {
var group = parseInt(i/8)
/* The data is in big-endian format, shift it in. */
vals[group] <<= 1;
/* This should be a high bit, based on the average. */
if (data[i] >= avg)
vals[group] |= 1;
}
/*
* Occasionally the final checksum test can be valid even when the
* values are clearly bogus. Perform additional sanity checks to
* ensure they are within the limitations of the DHT11.
*/
/* Relative humidity range is 20 - 90% */
if (vals[0] < 20 || vals[0] > 90) {
dbg("Bad humidity: %d%%", vals[0]);
return false;
}
/* Temperature range is 0 - 50C */
if (vals[2] > 50) {
dbg("Bad temperature: %d", vals[0]);
return false;
}
/*
* Validate the checksum and return whether successful or not. The
* checksum is simply the value of the other 4 groups combined.
*
* In theory the total should be masked off to 8-bits, but in testing
* this has occasionally resulted in obviously bogus data passing the
* test. It's unlikely that valid data will total >255 anyway given
* the limitations of the DHT11 and the lack of decimal precision in
* many implementations.
*/
if ((vals[0] + vals[1] + vals[2] + vals[3]) != vals[4]) {
dbg("Bad checksum: %d:%d:%d:%d %d", v[0], v[1], v[2], v[3], v[4]);
return false;
}
return true;
}
/*
* Run until the user kills the process, skipping any bad reads.
*/
var v = Buffer(5);
while (true) {
/*
* On some DHT11 the fractional parts are always 0, but print them out
* anyway as some models appear to at least support temperatures.
*
* On a successful read wait 5 seconds before the next sample. On a
* failed read, wait 1 second, which is the minimum time recommended
* by the datasheet between samples.
*/
if (read_dht11(v)) {
console.log("Temperature = %d.%dC, Humidity = %d.%d%%",
v[2], v[3], v[0], v[1]);
rpio.sleep(5);
} else {
rpio.sleep(1);
}
}