Skip to content

RFC: Additional DHT sensor support, including new I2C versions #2290

@mcauser

Description

@mcauser

I would like to improve the DHT driver and add support for an additional 14 sensors.

I have been experimenting with a number of DHT sensors (Aosong AM23xx series) and have discovered there are 4 main types:

Type 1: low-resolution digital (unique to DHT11)

  • interface: 1-wire
  • humidity resolution: 1 %RH
  • temperature resolution: 1 °C
    Sensors: DHT11

Type 2: digital (AM230x)

  • interface: 1-wire
  • humidity resolution: 0.1 %RH
  • temperature resolution: 0.1 °C
    Sensors: AM2301, DHT22 (AM2302), AM2302 (Wired), DHT33 (RHT04), AM2303, AM2305 (DHT44), AM2306

Type 3: digital and I2C (AM232x)

  • interface: 1-wire, I2C
  • humidity resolution: 0.1 %RH
  • temperature resolution: 0.1 °C
    Sensors: DHT12, AM2320, AM2321, AM2322, AM2325

Type 4: I2C (AM231x)

  • interface: I2C
  • humidity resolution: 0.1 %RH
  • temperature resolution: 0.1 °C
    Sensors: AM2311, AM2312, AM2313, AM2315

With the exception of the DHT11 sensor, all of them share the same custom 1-wire protocol (unrelated to Dallas).
All of the newer sensors which have an I2C interface, have the same device and register addresses.
They are all interchangeable, with range, accuracy, stability, current draw, speed and cost being the only differences.

All of the dual digital + I2C sensors can be put in digital mode by grounding the 4th pin (SCL).

I have compiled specifications for each sensor from various English and Chinese datasheets:
https://docs.google.com/spreadsheets/d/1jbSpU-rLXuba9aubcYI15_6hI2wM7-vmQ4iPcAV7MI4/edit

I would like to update the MicroPython ESP8266 DHT driver to support all of these sensors.
I have prototyped the I2C version and it works with my DHT12.
I can test the rest of the I2C sensors once they arrive in the mail.

I added this to /scripts/dht.py and flashed to my device:

class DHTBaseI2C:
    def __init__(self, i2c, addr):
        self.i2c = i2c
        self.addr = addr
        self.buf = bytearray(5)
    def measure(self):
        buf = self.buf
        self.i2c.readfrom_mem_into(self.addr, 0, buf)
        if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]:
            raise Exception("checksum error")

class DHT12_I2C(DHTBaseI2C):
    def humidity(self):
        return self.buf[0] + self.buf[1] * 0.1
    def temperature(self):
        t = self.buf[2] + (self.buf[3] & 0x7F) * 0.1
        if self.buf[3] & 0x80:
            t = -t
        return t

It works, but it can be done better.

Here is it working with a DHT12 and a WeMos D1 Mini.

Connections:

WeMos D1 Mini    DHT12
3V3 ------------ 1 (VDD)
D2 (GPIO4) ----- 2 (SDA)
GND ------------ 3 (GND)
D1 (GPIO5) ----- 4 (SCL)
import ustruct
import time, dht, machine
from machine import I2C, Pin
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=20000)
d = DHT12_I2C(i2c, 92)
while True:
    d.measure()
    print(d.temperature(), d.humidity())
    time.sleep_ms(1000)

I am not sure of the most pythonic way to structure this as each new dual interface sensor can potentially have 2x base classes, 1-wire and I2C.
They are constructed with either a single digital pin, or an I2C object + device address.
Constructor overloading?

There is also 16 DHT sensors, with probably more on the way.
They all fall into the type categories I have detailed above.
Should we have a class per type of sensor? eg. DHT11, DHT_OneWire, DHT_I2C?
A class for each of the product ranges? eg. DHT11, DHT12, AM230x, AM231x, AM232x?

Hoping someone with a bit more Python experience can help with the structure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions