Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RPi (non-pulseio) support #18

Merged
merged 5 commits into from
Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)