Compare commits

...

2 Commits

7 changed files with 340 additions and 11 deletions

21
DHT11_Python/LICENSE.md Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Zoltan Szarvas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

44
DHT11_Python/README.md Normal file
View File

@ -0,0 +1,44 @@
# DHT11 Python library
This simple class can be used for reading temperature and humidity values from DHT11 sensor on Raspberry Pi.
# Installation
To install, just run following:
```
pip install dht11
```
# Usage
1. Instantiate the `DHT11` class with the pin number as constructor parameter.
2. Call `read()` method, which will return `DHT11Result` object with actual values and error code.
For example:
```python
import RPi.GPIO as GPIO
import dht11
# initialize GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()
# read data using pin 14
instance = dht11.DHT11(pin = 14)
result = instance.read()
if result.is_valid():
print("Temperature: %-3.1f C" % result.temperature)
print("Humidity: %-3.1f %%" % result.humidity)
else:
print("Error: %d" % result.error_code)
```
For working example, see `dht11_example.py` (you probably need to adjust pin for your configuration)
# License
This project is licensed under the terms of the MIT license.

View File

@ -0,0 +1,203 @@
import time
import RPi
class DHT11Result:
'DHT11 sensor result returned by DHT11.read() method'
ERR_NO_ERROR = 0
ERR_MISSING_DATA = 1
ERR_CRC = 2
error_code = ERR_NO_ERROR
temperature = -1
humidity = -1
def __init__(self, error_code, temperature, humidity):
self.error_code = error_code
self.temperature = temperature
self.humidity = humidity
def is_valid(self):
return self.error_code == DHT11Result.ERR_NO_ERROR
class DHT11:
'DHT11 sensor reader class for Raspberry'
__pin = 0
def __init__(self, pin):
self.__pin = pin
def read(self):
RPi.GPIO.setup(self.__pin, RPi.GPIO.OUT)
# send initial high
self.__send_and_sleep(RPi.GPIO.HIGH, 0.05)
# pull down to low
self.__send_and_sleep(RPi.GPIO.LOW, 0.02)
# change to input using pull up
RPi.GPIO.setup(self.__pin, RPi.GPIO.IN, RPi.GPIO.PUD_UP)
# collect data into an array
data = self.__collect_input()
# parse lengths of all data pull up periods
pull_up_lengths = self.__parse_data_pull_up_lengths(data)
# if bit count mismatch, return error (4 byte data + 1 byte checksum)
if len(pull_up_lengths) != 40:
return DHT11Result(DHT11Result.ERR_MISSING_DATA, 0, 0)
# calculate bits from lengths of the pull up periods
bits = self.__calculate_bits(pull_up_lengths)
# we have the bits, calculate bytes
the_bytes = self.__bits_to_bytes(bits)
# calculate checksum and check
checksum = self.__calculate_checksum(the_bytes)
if the_bytes[4] != checksum:
return DHT11Result(DHT11Result.ERR_CRC, 0, 0)
# ok, we have valid data
# The meaning of the return sensor values
# the_bytes[0]: humidity int
# the_bytes[1]: humidity decimal
# the_bytes[2]: temperature int
# the_bytes[3]: temperature decimal
temperature = the_bytes[2] + float(the_bytes[3]) / 10
humidity = the_bytes[0] + float(the_bytes[1]) / 10
return DHT11Result(DHT11Result.ERR_NO_ERROR, temperature, humidity)
def __send_and_sleep(self, output, sleep):
RPi.GPIO.output(self.__pin, output)
time.sleep(sleep)
def __collect_input(self):
# collect the data while unchanged found
unchanged_count = 0
# this is used to determine where is the end of the data
max_unchanged_count = 100
last = -1
data = []
while True:
current = RPi.GPIO.input(self.__pin)
data.append(current)
if last != current:
unchanged_count = 0
last = current
else:
unchanged_count += 1
if unchanged_count > max_unchanged_count:
break
return data
def __parse_data_pull_up_lengths(self, data):
STATE_INIT_PULL_DOWN = 1
STATE_INIT_PULL_UP = 2
STATE_DATA_FIRST_PULL_DOWN = 3
STATE_DATA_PULL_UP = 4
STATE_DATA_PULL_DOWN = 5
state = STATE_INIT_PULL_DOWN
lengths = [] # will contain the lengths of data pull up periods
current_length = 0 # will contain the length of the previous period
for i in range(len(data)):
current = data[i]
current_length += 1
if state == STATE_INIT_PULL_DOWN:
if current == RPi.GPIO.LOW:
# ok, we got the initial pull down
state = STATE_INIT_PULL_UP
continue
else:
continue
if state == STATE_INIT_PULL_UP:
if current == RPi.GPIO.HIGH:
# ok, we got the initial pull up
state = STATE_DATA_FIRST_PULL_DOWN
continue
else:
continue
if state == STATE_DATA_FIRST_PULL_DOWN:
if current == RPi.GPIO.LOW:
# we have the initial pull down, the next will be the data pull up
state = STATE_DATA_PULL_UP
continue
else:
continue
if state == STATE_DATA_PULL_UP:
if current == RPi.GPIO.HIGH:
# data pulled up, the length of this pull up will determine whether it is 0 or 1
current_length = 0
state = STATE_DATA_PULL_DOWN
continue
else:
continue
if state == STATE_DATA_PULL_DOWN:
if current == RPi.GPIO.LOW:
# pulled down, we store the length of the previous pull up period
lengths.append(current_length)
state = STATE_DATA_PULL_UP
continue
else:
continue
return lengths
def __calculate_bits(self, pull_up_lengths):
# find shortest and longest period
shortest_pull_up = 1000
longest_pull_up = 0
for i in range(0, len(pull_up_lengths)):
length = pull_up_lengths[i]
if length < shortest_pull_up:
shortest_pull_up = length
if length > longest_pull_up:
longest_pull_up = length
# use the halfway to determine whether the period it is long or short
halfway = shortest_pull_up + (longest_pull_up - shortest_pull_up) / 2
bits = []
for i in range(0, len(pull_up_lengths)):
bit = False
if pull_up_lengths[i] > halfway:
bit = True
bits.append(bit)
return bits
def __bits_to_bytes(self, bits):
the_bytes = []
byte = 0
for i in range(0, len(bits)):
byte = byte << 1
if (bits[i]):
byte = byte | 1
else:
byte = byte | 0
if ((i + 1) % 8 == 0):
the_bytes.append(byte)
byte = 0
return the_bytes
def __calculate_checksum(self, the_bytes):
return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255

26
DHT11_Python/example.py Normal file
View File

@ -0,0 +1,26 @@
import RPi.GPIO as GPIO
import dht11
import time
import datetime
# initialize GPIO
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
# read data using pin 14
instance = dht11.DHT11(pin=14)
try:
while True:
result = instance.read()
if result.is_valid():
print("Last valid input: " + str(datetime.datetime.now()))
print("Temperature: %-3.1f C" % result.temperature)
print("Humidity: %-3.1f %%" % result.humidity)
time.sleep(6)
except KeyboardInterrupt:
print("Cleanup")
GPIO.cleanup()

23
DHT11_Python/setup.py Normal file
View File

@ -0,0 +1,23 @@
from setuptools import setup, find_packages
with open("README.md", "r") as fh:
long_description = fh.read()
setup(
name="dht11",
version="0.1.0",
author="Zoltán Szarvas",
author_email="",
description="Pure Python library for reading DHT11 sensor on Raspberry Pi",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/szazo/DHT11_Python",
packages=find_packages(),
install_requires=["RPi.GPIO"],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
)

View File

@ -56,6 +56,7 @@ if [ ! -d "$PROJECT_DIR" ]; then
echo -e "$line\nCreating 'dht11-sensor' in Desktop directory for current user.\n$line\n"
mkdir -p "$PROJECT_DIR"
cp "./temp-calc.py" "$PROJECT_DIR/"
cp -r "./DHT11_Python/" "$PROJECT_DIR/DHT11_Python"
echo -e "$line\nCreated '$PROJECT_DIR' directory.\n$line\n"
else
echo -e "$line\n$PROJECT_DIR already exists. Please delete the folder before running this script.\n$line\n\nExiting..."
@ -71,6 +72,12 @@ echo -e "$line\nActivating virtual environment...\n$line\n"
source $PROJECT_DIR/bin/activate
echo -e "$line\nInstalling dependencies...\n$line\n"
pip3 install --upgrade RPi.GPIO setuptools dht11
pip install --upgrade RPi.GPIO setuptools
# Alternatively, instead of executing the next four lines, you can also run "pip install dht11"
# but I've decided to keep the files for "dht11" package locally available for installation in the script.
cd "$PROJECT_DIR/DHT11_Python"
pip install .
pip show dht11
cd "$PROJECT_DIR/"
echo -e "\n\n\n$line$line$line\nSetup completed.\nExecute the command 'python3 temp-calc.py' to calculate the temperature.\n# DESIGNED AND ENGINEERED BY KSHITIJ.\n# END OF SCRIPT\n$line$line$line\n\n\n"

View File

@ -2,12 +2,15 @@
import RPi.GPIO as GPIO
import dht11
import time
# initialize GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()
try:
while True:
# read data using pin 16
instance = dht11.DHT11(pin = 16)
result = instance.read()
@ -17,5 +20,7 @@ if result.is_valid():
print("Humidity: %-3.1f %%" % result.humidity)
else:
print("Error: %d" % result.error_code)
time.sleep(3)
except KeyboardInterrupt:
print("Program stopped by user.")
GPIO.cleanup()