30
30
31
31
import array
32
32
import time
33
+ from digitalio import DigitalInOut , Pull , Direction
34
+ _USE_PULSEIO = False
33
35
try :
34
36
import pulseio
35
- except ImportError as excpt :
36
- print ( "adafruit_dht requires the pulseio library, but it failed to load." +
37
- " Note that CircuitPython does not support pulseio on all boards." )
38
- raise excpt
37
+ _USE_PULSEIO = True
38
+ except ImportError :
39
+ pass # This is OK, we'll try to bitbang it!
40
+
39
41
40
42
__version__ = "0.0.0-auto.0"
41
43
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DHT.git"
@@ -89,7 +91,7 @@ def _pulses_to_binary(self, pulses, start, stop):
89
91
90
92
return binary
91
93
92
- def _get_pulses (self ):
94
+ def _get_pulses_pulseio (self ):
93
95
""" _get_pulses implements the communication protcol for
94
96
DHT11 and DHT22 type devices. It sends a start signal
95
97
of a specific length and listens and measures the
@@ -100,10 +102,8 @@ def _get_pulses(self):
100
102
pulses will have 81 elements for the DHT11/22 type devices.
101
103
"""
102
104
pulses = array .array ('H' )
103
-
104
105
# create the PulseIn object using context manager
105
106
with pulseio .PulseIn (self ._pin , 81 , True ) as pulse_in :
106
-
107
107
# The DHT type device use a specialize 1-wire protocol
108
108
# The microprocessor first sends a LOW signal for a
109
109
# specific length of time. Then the device sends back a
@@ -112,19 +112,51 @@ def _get_pulses(self):
112
112
pulse_in .pause ()
113
113
pulse_in .clear ()
114
114
pulse_in .resume (self ._trig_wait )
115
-
116
115
# loop until we get the return pulse we need or
117
116
# time out after 1/4 second
118
117
tmono = time .monotonic ()
119
- while True :
120
- if time .monotonic ()- tmono > 0.25 : # time out after 1/4 seconds
121
- break
122
-
118
+ while time .monotonic () - tmono < 0.25 :
119
+ pass # time out after 1/4 seconds
123
120
pulse_in .pause ()
124
121
while pulse_in :
125
122
pulses .append (pulse_in .popleft ())
126
123
pulse_in .resume ()
124
+ return pulses
125
+
126
+ def _get_pulses_bitbang (self ):
127
+ """ _get_pulses implements the communication protcol for
128
+ DHT11 and DHT22 type devices. It sends a start signal
129
+ of a specific length and listens and measures the
130
+ return signal lengths.
127
131
132
+ return pulses (array.array uint16) contains alternating high and low
133
+ transition times starting with a low transition time. Normally
134
+ pulses will have 81 elements for the DHT11/22 type devices.
135
+ """
136
+ pulses = array .array ('H' )
137
+ with DigitalInOut (self ._pin ) as dhtpin :
138
+ # we will bitbang if no pulsein capability
139
+ transitions = []
140
+ # Signal by setting pin high, then low, and releasing
141
+ dhtpin .direction = Direction .OUTPUT
142
+ dhtpin .value = True
143
+ time .sleep (0.1 )
144
+ dhtpin .value = False
145
+ time .sleep (0.001 )
146
+ timestamp = time .monotonic () # take timestamp
147
+ dhtval = True # start with dht pin true because its pulled up
148
+ dhtpin .direction = Direction .INPUT
149
+ dhtpin .pull = Pull .UP
150
+ while time .monotonic () - timestamp < 0.25 :
151
+ if dhtval != dhtpin .value :
152
+ dhtval = not dhtval # we toggled
153
+ transitions .append (time .monotonic ()) # save the timestamp
154
+ # convert transtions to microsecond delta pulses:
155
+ # use last 81 pulses
156
+ transition_start = max (1 , len (transitions ) - 81 )
157
+ for i in range (transition_start , len (transitions )):
158
+ pulses_micro_sec = int (1000000 * (transitions [i ] - transitions [i - 1 ]))
159
+ pulses .append (min (pulses_micro_sec , 65535 ))
128
160
return pulses
129
161
130
162
def measure (self ):
@@ -135,17 +167,19 @@ def measure(self):
135
167
Raises RuntimeError exception for checksum failure and for insuffcient
136
168
data returned from the device (try again)
137
169
"""
138
- delay_between_readings = 0.5
139
- if self ._dht11 :
140
- delay_between_readings = 1.0
170
+ delay_between_readings = 2 # 2 seconds per read according to datasheet
141
171
# Initiate new reading if this is the first call or if sufficient delay
142
172
# If delay not sufficient - return previous reading.
143
173
# This allows back to back access for temperature and humidity for same reading
144
174
if (self ._last_called == 0 or
145
175
(time .monotonic ()- self ._last_called ) > delay_between_readings ):
146
176
self ._last_called = time .monotonic ()
147
177
148
- pulses = self ._get_pulses ()
178
+ if _USE_PULSEIO :
179
+ pulses = self ._get_pulses_pulseio ()
180
+ else :
181
+ pulses = self ._get_pulses_bitbang ()
182
+ #print(len(pulses), "pulses:", [x for x in pulses])
149
183
150
184
if len (pulses ) >= 80 :
151
185
buf = array .array ('B' )
@@ -155,14 +189,11 @@ def measure(self):
155
189
if self ._dht11 :
156
190
# humidity is 1 byte
157
191
self ._humidity = buf [0 ]
158
- else :
159
- # humidity is 2 bytes
160
- self ._humidity = ((buf [0 ]<< 8 ) | buf [1 ]) / 10
161
-
162
- if self ._dht11 :
163
192
# temperature is 1 byte
164
193
self ._temperature = buf [2 ]
165
194
else :
195
+ # humidity is 2 bytes
196
+ self ._humidity = ((buf [0 ]<< 8 ) | buf [1 ]) / 10
166
197
# temperature is 2 bytes
167
198
# MSB is sign, bits 0-14 are magnitude)
168
199
raw_temperature = (((buf [2 ] & 0x7f )<< 8 ) | buf [3 ]) / 10
@@ -180,9 +211,12 @@ def measure(self):
180
211
# check sum failed to validate
181
212
raise RuntimeError ("Checksum did not validate. Try again." )
182
213
183
- else :
214
+ elif len (pulses ) >= 10 :
215
+ # We got *some* data just not 81 bits
184
216
raise RuntimeError ("A full buffer was not returned. Try again." )
185
-
217
+ else :
218
+ # Probably a connection issue!
219
+ raise RuntimeError ("DHT sensor not found, check wiring" )
186
220
@property
187
221
def temperature (self ):
188
222
""" temperature current reading. It makes sure a reading is available
0 commit comments