Skip to content

Commit

Permalink
Merge pull request #18 from jerryneedell/jerryn_fix_pr_14
Browse files Browse the repository at this point in the history
Add RPi (non-pulseio) support
  • Loading branch information
tannewt authored Oct 23, 2018
2 parents 5493703 + 1051579 commit 5dbcca1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 31 deletions.
80 changes: 57 additions & 23 deletions adafruit_dht.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@

import array
import time
from digitalio import DigitalInOut, Pull, Direction
_USE_PULSEIO = False
try:
import pulseio
except ImportError as excpt:
print("adafruit_dht requires the pulseio library, but it failed to load."+
" Note that CircuitPython does not support pulseio on all boards.")
raise excpt
_USE_PULSEIO = True
except ImportError:
pass # This is OK, we'll try to bitbang it!


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

return binary

def _get_pulses(self):
def _get_pulses_pulseio(self):
""" _get_pulses implements the communication protcol for
DHT11 and DHT22 type devices. It sends a start signal
of a specific length and listens and measures the
Expand All @@ -100,10 +102,8 @@ def _get_pulses(self):
pulses will have 81 elements for the DHT11/22 type devices.
"""
pulses = array.array('H')

# create the PulseIn object using context manager
with pulseio.PulseIn(self._pin, 81, True) as pulse_in:

# The DHT type device use a specialize 1-wire protocol
# The microprocessor first sends a LOW signal for a
# specific length of time. Then the device sends back a
Expand All @@ -112,19 +112,51 @@ def _get_pulses(self):
pulse_in.pause()
pulse_in.clear()
pulse_in.resume(self._trig_wait)

# loop until we get the return pulse we need or
# time out after 1/4 second
tmono = time.monotonic()
while True:
if time.monotonic()-tmono > 0.25: # time out after 1/4 seconds
break

while time.monotonic() - tmono < 0.25:
pass # time out after 1/4 seconds
pulse_in.pause()
while pulse_in:
pulses.append(pulse_in.popleft())
pulse_in.resume()
return pulses

def _get_pulses_bitbang(self):
""" _get_pulses implements the communication protcol for
DHT11 and DHT22 type devices. It sends a start signal
of a specific length and listens and measures the
return signal lengths.
return pulses (array.array uint16) contains alternating high and low
transition times starting with a low transition time. Normally
pulses will have 81 elements for the DHT11/22 type devices.
"""
pulses = array.array('H')
with DigitalInOut(self._pin) as dhtpin:
# we will bitbang if no pulsein capability
transitions = []
# Signal by setting pin high, then low, and releasing
dhtpin.direction = Direction.OUTPUT
dhtpin.value = True
time.sleep(0.1)
dhtpin.value = False
time.sleep(0.001)
timestamp = time.monotonic() # take timestamp
dhtval = True # start with dht pin true because its pulled up
dhtpin.direction = Direction.INPUT
dhtpin.pull = Pull.UP
while time.monotonic() - timestamp < 0.25:
if dhtval != dhtpin.value:
dhtval = not dhtval # we toggled
transitions.append(time.monotonic()) # save the timestamp
# convert transtions to microsecond delta pulses:
# use last 81 pulses
transition_start = max(1, len(transitions) - 81)
for i in range(transition_start, len(transitions)):
pulses_micro_sec = int(1000000 * (transitions[i] - transitions[i-1]))
pulses.append(min(pulses_micro_sec, 65535))
return pulses

def measure(self):
Expand All @@ -135,17 +167,19 @@ def measure(self):
Raises RuntimeError exception for checksum failure and for insuffcient
data returned from the device (try again)
"""
delay_between_readings = 0.5
if self._dht11:
delay_between_readings = 1.0
delay_between_readings = 2 # 2 seconds per read according to datasheet
# Initiate new reading if this is the first call or if sufficient delay
# If delay not sufficient - return previous reading.
# This allows back to back access for temperature and humidity for same reading
if (self._last_called == 0 or
(time.monotonic()-self._last_called) > delay_between_readings):
self._last_called = time.monotonic()

pulses = self._get_pulses()
if _USE_PULSEIO:
pulses = self._get_pulses_pulseio()
else:
pulses = self._get_pulses_bitbang()
#print(len(pulses), "pulses:", [x for x in pulses])

if len(pulses) >= 80:
buf = array.array('B')
Expand All @@ -155,14 +189,11 @@ def measure(self):
if self._dht11:
# humidity is 1 byte
self._humidity = buf[0]
else:
# humidity is 2 bytes
self._humidity = ((buf[0]<<8) | buf[1]) / 10

if self._dht11:
# temperature is 1 byte
self._temperature = buf[2]
else:
# humidity is 2 bytes
self._humidity = ((buf[0]<<8) | buf[1]) / 10
# temperature is 2 bytes
# MSB is sign, bits 0-14 are magnitude)
raw_temperature = (((buf[2] & 0x7f)<<8) | buf[3]) / 10
Expand All @@ -180,9 +211,12 @@ def measure(self):
# check sum failed to validate
raise RuntimeError("Checksum did not validate. Try again.")

else:
elif len(pulses) >= 10:
# We got *some* data just not 81 bits
raise RuntimeError("A full buffer was not returned. Try again.")

else:
# Probably a connection issue!
raise RuntimeError("DHT sensor not found, check wiring")
@property
def temperature(self):
""" temperature current reading. It makes sure a reading is available
Expand Down
17 changes: 10 additions & 7 deletions examples/dht_simpletest.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import time
from board import D2
import board
import adafruit_dht

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

while True:
try:
# show the values to the serial port
temperature = dhtDevice.temperature * (9 / 5) + 32
# Print the values to the serial port
temperature_c = dhtDevice.temperature
temperature_f = temperature_c * (9 / 5) + 32
humidity = dhtDevice.humidity
print("Temp: {:.1f} F Humidity: {}% ".format(temperature, humidity))
print("Temp: {:.1f} F / {:.1f} C Humidity: {}% "
.format(temperature_f, temperature_c, humidity))

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

time.sleep(2.0)
2 changes: 1 addition & 1 deletion examples/dht_to_led_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@
display.show()

except RuntimeError as error:
print(error.args)
print(error.args[0])

time.sleep(2.0)

0 comments on commit 5dbcca1

Please sign in to comment.