Skip to content

Commit 5dbcca1

Browse files
authored
Merge pull request #18 from jerryneedell/jerryn_fix_pr_14
Add RPi (non-pulseio) support
2 parents 5493703 + 1051579 commit 5dbcca1

File tree

3 files changed

+68
-31
lines changed

3 files changed

+68
-31
lines changed

adafruit_dht.py

+57-23
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@
3030

3131
import array
3232
import time
33+
from digitalio import DigitalInOut, Pull, Direction
34+
_USE_PULSEIO = False
3335
try:
3436
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+
3941

4042
__version__ = "0.0.0-auto.0"
4143
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DHT.git"
@@ -89,7 +91,7 @@ def _pulses_to_binary(self, pulses, start, stop):
8991

9092
return binary
9193

92-
def _get_pulses(self):
94+
def _get_pulses_pulseio(self):
9395
""" _get_pulses implements the communication protcol for
9496
DHT11 and DHT22 type devices. It sends a start signal
9597
of a specific length and listens and measures the
@@ -100,10 +102,8 @@ def _get_pulses(self):
100102
pulses will have 81 elements for the DHT11/22 type devices.
101103
"""
102104
pulses = array.array('H')
103-
104105
# create the PulseIn object using context manager
105106
with pulseio.PulseIn(self._pin, 81, True) as pulse_in:
106-
107107
# The DHT type device use a specialize 1-wire protocol
108108
# The microprocessor first sends a LOW signal for a
109109
# specific length of time. Then the device sends back a
@@ -112,19 +112,51 @@ def _get_pulses(self):
112112
pulse_in.pause()
113113
pulse_in.clear()
114114
pulse_in.resume(self._trig_wait)
115-
116115
# loop until we get the return pulse we need or
117116
# time out after 1/4 second
118117
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
123120
pulse_in.pause()
124121
while pulse_in:
125122
pulses.append(pulse_in.popleft())
126123
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.
127131
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))
128160
return pulses
129161

130162
def measure(self):
@@ -135,17 +167,19 @@ def measure(self):
135167
Raises RuntimeError exception for checksum failure and for insuffcient
136168
data returned from the device (try again)
137169
"""
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
141171
# Initiate new reading if this is the first call or if sufficient delay
142172
# If delay not sufficient - return previous reading.
143173
# This allows back to back access for temperature and humidity for same reading
144174
if (self._last_called == 0 or
145175
(time.monotonic()-self._last_called) > delay_between_readings):
146176
self._last_called = time.monotonic()
147177

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])
149183

150184
if len(pulses) >= 80:
151185
buf = array.array('B')
@@ -155,14 +189,11 @@ def measure(self):
155189
if self._dht11:
156190
# humidity is 1 byte
157191
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:
163192
# temperature is 1 byte
164193
self._temperature = buf[2]
165194
else:
195+
# humidity is 2 bytes
196+
self._humidity = ((buf[0]<<8) | buf[1]) / 10
166197
# temperature is 2 bytes
167198
# MSB is sign, bits 0-14 are magnitude)
168199
raw_temperature = (((buf[2] & 0x7f)<<8) | buf[3]) / 10
@@ -180,9 +211,12 @@ def measure(self):
180211
# check sum failed to validate
181212
raise RuntimeError("Checksum did not validate. Try again.")
182213

183-
else:
214+
elif len(pulses) >= 10:
215+
# We got *some* data just not 81 bits
184216
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")
186220
@property
187221
def temperature(self):
188222
""" temperature current reading. It makes sure a reading is available

examples/dht_simpletest.py

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import time
2-
from board import D2
2+
import board
33
import adafruit_dht
44

5-
#initial the dht device
6-
dhtDevice = adafruit_dht.DHT22(D2)
5+
# Initial the dht device, with data pin connected to:
6+
dhtDevice = adafruit_dht.DHT22(board.D18)
77

88
while True:
99
try:
10-
# show the values to the serial port
11-
temperature = dhtDevice.temperature * (9 / 5) + 32
10+
# Print the values to the serial port
11+
temperature_c = dhtDevice.temperature
12+
temperature_f = temperature_c * (9 / 5) + 32
1213
humidity = dhtDevice.humidity
13-
print("Temp: {:.1f} F Humidity: {}% ".format(temperature, humidity))
14+
print("Temp: {:.1f} F / {:.1f} C Humidity: {}% "
15+
.format(temperature_f, temperature_c, humidity))
1416

1517
except RuntimeError as error:
16-
print(error.args)
18+
# Errors happen fairly often, DHT's are hard to read, just keep going
19+
print(error.args[0])
1720

1821
time.sleep(2.0)

examples/dht_to_led_display.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@
3535
display.show()
3636

3737
except RuntimeError as error:
38-
print(error.args)
38+
print(error.args[0])
3939

4040
time.sleep(2.0)

0 commit comments

Comments
 (0)