Skip to content

Commit

Permalink
Merge pull request #1367 from Joe2824/master
Browse files Browse the repository at this point in the history
Add DHT20 Humidity/Temperature Sensor
  • Loading branch information
kizniche authored Apr 4, 2024
2 parents 5f2d053 + d41b53e commit d7fd497
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This release changes the install directory from ~/Mycodo to /opt/Mycodo. This ne

### Features

- Add Input: DHT20
- Add Output: GPIO On/Off using pinctrl (First Pi 5-compatible Output)
- Add Output: PWM MQTT Publish
- Add Output: GP8403 2-Channel DAC (0-10 VDC) ([#1354](https://github.com/kizniche/Mycodo/issues/1354))
Expand Down
177 changes: 177 additions & 0 deletions mycodo/inputs/dht20.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# coding=utf-8
import copy
import time

from mycodo.inputs.base_input import AbstractInput
from mycodo.inputs.sensorutils import calculate_dewpoint
from mycodo.inputs.sensorutils import calculate_vapor_pressure_deficit

# Measurements
measurements_dict = {
0: {
'measurement': 'temperature',
'unit': 'C'
},
1: {
'measurement': 'humidity',
'unit': 'percent'
},
2: {
'measurement': 'dewpoint',
'unit': 'C'
},
3: {
'measurement': 'vapor_pressure_deficit',
'unit': 'Pa'
}
}

# Input information
INPUT_INFORMATION = {
'input_name_unique': 'DHT20',
'input_manufacturer': 'AOSONG',
'input_name': 'DHT20',
'input_library': 'smbus2',
'measurements_name': 'Humidity/Temperature',
'measurements_dict': measurements_dict,
'url_datasheet': 'http://www.aosong.com/userfiles/files/media/Data%20Sheet%20DHT20%20%20A1.pdf',
'url_product_purchase': [
'https://www.seeedstudio.com/Grove-Temperature-Humidity-Sensor-V2-0-DHT20-p-4967.html',
'https://www.antratek.de/humidity-and-temperature-sensor-dht20',
'https://www.adafruit.com/product/5183'],
'url_manufacturer': 'https://asairsensors.com/product/dht20-sip-packaged-temperature-and-humidity-sensor/',

'options_enabled': [
'measurements_select',
'period',
'pre_output'
],

'options_disabled': [
'interface',
'i2c_location',
],

'dependencies_module': [
('pip-pypi', 'smbus2', 'smbus2==0.4.1')
],

'interfaces': ['I2C'],
'i2c_location': ['0x38'],
'self.i2c_address_editable': False,
}


class InputModule(AbstractInput):
"""
This module is a modified version of the DHT20 module from the Mycodo
distribution.
A sensor support class that measures the DHT20's humidity and temperature
and calculates the dew point.
"""
def __init__(self, input_dev, testing=False):
"""
Instantiate with the Pi and gpio to which the DHT20 output
pin is connected.
"""
super().__init__(input_dev, testing=testing, name=__name__)

self.i2c_address = None
self.dht20 = None

if not testing:
self.try_initialize()

def initialize(self):
from smbus2 import SMBus

# Wait 100ms after power-on
time.sleep(0.1)

self.i2c_address = int(str(self.input_dev.i2c_location), 16)
self.dht20 = SMBus(self.input_dev.i2c_bus)

# Check if Sensor is ready
status_word = self.dht20.read_byte(self.self.i2c_address)
if status_word != 0x18:
buffer = bytearray(b'\x00\x00')
# Initialize the 0x1B, 0x1C, 0x1E registers
self.dht20.write_i2c_block_data(self.i2c_address, 0x1B, buffer)
self.dht20.write_i2c_block_data(self.i2c_address, 0x1C, buffer)
self.dht20.write_i2c_block_data(self.i2c_address, 0x1E, buffer)
time.sleep(1)

if self.dht20.read_byte(self.i2c_address) != 0x18:
self.logger.error("Could not initialize DHT20.")
else:
self.logger.debug("Initialize DHT20 successfully.")

def calculate_crc(self, data):
data = data[:-1]
crc = 0xFF # Initial value of CRC
polynomial = 0x31 # CRC8 check polynomial: 1 + X^4 + X^5 + X^8

for byte in data:
crc ^= byte # XOR operation with the current byte
for _ in range(8):
if crc & 0x80: # Check if the most significant bit is 1
crc = (crc << 1) ^ polynomial
else:
crc <<= 1
return crc & 0xFF # Return only the 8 least significant bits

def get_measurement(self):
"""Gets the humidity and temperature
'temperature': temperature (°C),
'raw_temperature': the 'raw' temperature as produced by the ADC,
'humidity': relative humidity (%RH),
'raw_humidity': the 'raw' relative humidity as produced by the ADC,
'crc_ok': indicates if the data was received correctly
"""
self.return_dict = copy.deepcopy(measurements_dict)

time.sleep(0.01)
# trigger measurement
self.dht20.write_i2c_block_data(self.i2c_address,0xAC,[0x33,0x00])
time.sleep(0.08)

# read measurement data
data = self.dht20.read_i2c_block_data(self.i2c_address,0x71,7)

received_crc = data[-1]
crc_ok = self.calculate_crc(data) == received_crc

if crc_ok:
raw_temperature = ((data[3] & 0xf) << 16) + (data[4] << 8) + data[5]
temperature = 200*float(raw_temperature)/2**20 - 50

raw_humidity = ((data[3] & 0xf0) >> 4) + (data[1] << 12) + (data[2] << 4)
humidity = 100*float(raw_humidity)/2**20

self.logger.debug(f"Temperature: {temperature}, Humidity: {humidity}, CRC OK: {crc_ok}")

if humidity:
temp_dew_point = calculate_dewpoint(temperature, humidity)
temp_vpd = calculate_vapor_pressure_deficit(temperature, humidity)
else:
self.logger.error("Could not acquire measurement")

if temp_dew_point is not None:
if self.is_enabled(0):
self.value_set(0, temperature)
if self.is_enabled(1):
self.value_set(1, humidity)
if self.is_enabled(2):
self.value_set(2, temp_dew_point)
if self.is_enabled(3):
self.value_set(3, temp_vpd)

else:
self.logger.error("CRC check was not successfully")

return self.return_dict

0 comments on commit d7fd497

Please sign in to comment.