From d4ec646fb2c3efa88f6ca152672bc4483b75b66c Mon Sep 17 00:00:00 2001 From: Jerry Needell Date: Wed, 17 Oct 2018 06:34:29 -0400 Subject: [PATCH 1/5] resolve pr_14 conflicts - fix bug with sample delay --- adafruit_dht.py | 91 ++++++++++++++++++++++------------ examples/dht_simpletest.py | 17 ++++--- examples/dht_to_led_display.py | 2 +- 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/adafruit_dht.py b/adafruit_dht.py index e4842c3..edf679c 100644 --- a/adafruit_dht.py +++ b/adafruit_dht.py @@ -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" @@ -101,30 +103,51 @@ def _get_pulses(self): """ 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 - # series HIGH and LOW signals. The length the HIGH signals - # represents the device values. - 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 - - pulse_in.pause() - while pulse_in: - pulses.append(pulse_in.popleft()) - pulse_in.resume() - + if _USE_PULSEIO: + # 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 + # series HIGH and LOW signals. The length the HIGH signals + # represents the device values. + 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 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() + else: + 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.1: + if dhtval != dhtpin.value: + dhtval = not dhtval # we toggled + transitions.append(time.monotonic()) # save the timestamp + # convert transtions to microsecond delta pulses: + for i in range(1, len(transitions)): + pulses_micro_sec = int(1000000 * (transitions[i] - transitions[i-1])) + pulses.append(min(pulses_micro_sec, 65535)) return pulses def measure(self): @@ -135,9 +158,7 @@ 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 @@ -146,6 +167,7 @@ def measure(self): self._last_called = time.monotonic() pulses = self._get_pulses() + #print(len(pulses), "pulses:", [x for x in pulses]) if len(pulses) >= 80: buf = array.array('B') @@ -180,9 +202,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 diff --git a/examples/dht_simpletest.py b/examples/dht_simpletest.py index 4686c4d..e07c078 100644 --- a/examples/dht_simpletest.py +++ b/examples/dht_simpletest.py @@ -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) diff --git a/examples/dht_to_led_display.py b/examples/dht_to_led_display.py index 3286f3b..d3cb3a9 100644 --- a/examples/dht_to_led_display.py +++ b/examples/dht_to_led_display.py @@ -35,6 +35,6 @@ display.show() except RuntimeError as error: - print(error.args) + print(error.args[0]) time.sleep(2.0) From de4f5f38f5fb25f89847f2e17c58b14519d1ec80 Mon Sep 17 00:00:00 2001 From: Jerry Needell Date: Wed, 17 Oct 2018 06:40:08 -0400 Subject: [PATCH 2/5] pylint - indent error --- adafruit_dht.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_dht.py b/adafruit_dht.py index edf679c..27e5e22 100644 --- a/adafruit_dht.py +++ b/adafruit_dht.py @@ -120,7 +120,7 @@ def _get_pulses(self): # time out after 1/4 second tmono = time.monotonic() while time.monotonic() - tmono < 0.25: - pass # time out after 1/4 seconds + pass # time out after 1/4 seconds pulse_in.pause() while pulse_in: pulses.append(pulse_in.popleft()) From d122696eda4a5e7858b23141ef67a556db4a5224 Mon Sep 17 00:00:00 2001 From: Jerry Needell Date: Wed, 17 Oct 2018 07:36:43 -0400 Subject: [PATCH 3/5] tweak to RPi pulse detect --- adafruit_dht.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adafruit_dht.py b/adafruit_dht.py index 27e5e22..5cd8748 100644 --- a/adafruit_dht.py +++ b/adafruit_dht.py @@ -145,7 +145,9 @@ def _get_pulses(self): dhtval = not dhtval # we toggled transitions.append(time.monotonic()) # save the timestamp # convert transtions to microsecond delta pulses: - for i in range(1, len(transitions)): + # 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 From d2da8739c030a66c5d17e731ed9debe9409e5e37 Mon Sep 17 00:00:00 2001 From: Jerry Needell Date: Wed, 17 Oct 2018 14:57:53 -0400 Subject: [PATCH 4/5] make delay for bitbang same as for pulseio --- adafruit_dht.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_dht.py b/adafruit_dht.py index 5cd8748..eebcdd6 100644 --- a/adafruit_dht.py +++ b/adafruit_dht.py @@ -140,7 +140,7 @@ def _get_pulses(self): dhtval = True # start with dht pin true because its pulled up dhtpin.direction = Direction.INPUT dhtpin.pull = Pull.UP - while time.monotonic() - timestamp < 0.1: + while time.monotonic() - timestamp < 0.25: if dhtval != dhtpin.value: dhtval = not dhtval # we toggled transitions.append(time.monotonic()) # save the timestamp From 105157930bfa10f0734f8ef308b11a8333583067 Mon Sep 17 00:00:00 2001 From: Jerry Needell Date: Thu, 18 Oct 2018 22:07:09 -0400 Subject: [PATCH 5/5] create private functions for pulseio and bitbang version of getting pulses --- adafruit_dht.py | 115 +++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/adafruit_dht.py b/adafruit_dht.py index eebcdd6..2860bee 100644 --- a/adafruit_dht.py +++ b/adafruit_dht.py @@ -91,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 @@ -102,54 +102,61 @@ 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 + # series HIGH and LOW signals. The length the HIGH signals + # represents the device values. + 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 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. - if _USE_PULSEIO: - # 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 - # series HIGH and LOW signals. The length the HIGH signals - # represents the device values. - 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 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() - else: - 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 (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): @@ -168,7 +175,10 @@ def measure(self): (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: @@ -179,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