diff --git a/adafruit_dht.py b/adafruit_dht.py index e4842c3..2860bee 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" @@ -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 @@ -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 @@ -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): @@ -135,9 +167,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 @@ -145,7 +175,11 @@ 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: buf = array.array('B') @@ -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 @@ -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 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)