# Development of driver for DHT11 single wire humidity & temperature sensor
# Copyright by Anthony Vogelaar, Perth Scotland
# rev 0.10  2025-08-27  initial release

from	machine		import	Pin, freq;		freq(240_000_000)
import	time
from	collections	import	deque

# ============================== Dht11 ===================================

# remark:
# by not using polling, although this requires separate read and write pins,
# the 19 mSec and 6 mSec delay are availabe for other tasks, ex. asyncio

# Driver for DHT11 humidity and temperature sensor
class DHT11:
    
    # One wire DHT11 I/O is connected to pin_rd and pin_wr
    def __init__(self, pin_rd=34, pin_wr=23):
        self.wr = Pin(pin_wr, Pin.OPEN_DRAIN, value=1)		# writing to DHT11
        self.rd = Pin(pin_rd, Pin.IN, Pin.PULL_UP)			# reading from DHT11
        self.rd.irq(self._onIrq, trigger=Pin.IRQ_RISING)
        self.fifo	= deque([], 50)							# collect time of up to 50 positive rd edges
        
    
    # return humidity and temperature
    def getHT(self):
        
        # decode fifo content into humidity and time
        def decode():
            res = 0											# bit accumulator
            t0 = self.fifo.popleft()						# time firs positive edge
            while self.fifo:
                t0, t1 = self.fifo.popleft(), t0			# delta time
                res = res << 1
                if time.ticks_diff(t0, t1) > 100: res += 1	# shift in LSB
            humidity    = (res >> 32 & 0xFF) + ((res >> 24 & 0xFF) / 10)	# res[1] + res[2] / 10
            temperature = (res >> 16 & 0xFF) + ((res >>  8 & 0xFF) / 10)	# res[3] + res[1] / 10
            return humidity, temperature
            
            
        self.wr(0)											# low for 19 mSec = start
        while self.fifo: self.fifo.popleft()				# empty fifo
        time.sleep_ms(19)
        self.wr(1)											# end of start
        time.sleep_ms(6)									# wait to collect incoming data
        return decode()										# return humidity and temperature as evaluated
        
        
    # save time of rising edge in fifo
    def _onIrq(self, sender):
        self.fifo.append(time.ticks_us())        

# ============================== test ====================================

if __name__ == '__main__':
    
    def test():
        dht11 = DHT11()
        h, t = dht11.getHT()
        print('humidity    =', h)
        print('temperature =', t)


    test()

# =============================== end ===================================
