dht22 implementation

This commit is contained in:
OMGeeky
2025-05-07 19:28:35 +02:00
parent 5d15df6bde
commit f5af3419d5
5 changed files with 581 additions and 0 deletions

116
README.md Normal file
View File

@@ -0,0 +1,116 @@
# ESP Sensors
A Python library for interfacing with various sensors on ESP32/ESP8266 microcontrollers using MicroPython.
## Overview
This library provides a simple and consistent interface for working with different types of sensors connected to ESP32/ESP8266 microcontrollers. It includes both real hardware implementations and simulation capabilities for testing without physical hardware.
## Features
- Base sensor class with common functionality
- Temperature sensor implementation
- DHT22 temperature and humidity sensor implementation
- Simulation mode for testing without hardware
- Comprehensive test suite
- Example scripts for each sensor type
## Installation
1. Install MicroPython on your ESP32/ESP8266 device
2. Clone this repository:
```bash
git clone https://github.com/yourusername/esp-sensors.git
cd esp-sensors
```
3. Install dependencies:
```bash
pip install -r requirements.txt
```
## Usage
### Temperature Sensor
```python
from src.esp_sensors.temperature import TemperatureSensor
# Initialize a temperature sensor on GPIO pin 5
sensor = TemperatureSensor("room_temp", 5, unit="C")
# Read temperature
temp = sensor.read()
print(f"Temperature: {temp}°C")
# Convert to Fahrenheit
temp_f = sensor.to_fahrenheit()
print(f"Temperature: {temp_f}°F")
```
### DHT22 Sensor
```python
from src.esp_sensors.dht22 import DHT22Sensor
# Initialize a DHT22 sensor on GPIO pin 4
sensor = DHT22Sensor("living_room", 4)
# Read temperature
temp = sensor.read()
print(f"Temperature: {temp}°C")
# Read humidity
humidity = sensor.read_humidity()
print(f"Humidity: {humidity}%")
```
## Available Sensors
| Sensor | Description | Features |
|--------|-------------|----------|
| Temperature | Basic temperature sensor | Temperature in C/F |
| DHT22 | Digital temperature and humidity sensor | Temperature in C/F, Humidity % |
## Examples
Example scripts are provided in the `examples/` directory:
- `examples/dht22_example.py`: Demonstrates how to use the DHT22 sensor
## Documentation
Detailed documentation for each sensor is available in the `docs/` directory:
- [DHT22 Sensor Documentation](docs/dht22_sensor.md)
## Development
### Setup Development Environment
```bash
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
```
### Running Tests
```bash
python -m pytest
```
### Code Style
This project uses Black for code formatting:
```bash
black .
```
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.

127
docs/dht22_sensor.md Normal file
View File

@@ -0,0 +1,127 @@
# DHT22 Sensor Implementation for ESP32
This document provides information about the DHT22 sensor implementation for ESP32 microcontrollers in this project.
## Overview
The DHT22 (also known as AM2302) is a digital temperature and humidity sensor that provides high-precision temperature and humidity readings. This implementation allows you to easily integrate DHT22 sensors with your ESP32 projects using MicroPython.
## Features
- Temperature readings in Celsius or Fahrenheit
- Humidity readings as percentage
- Automatic detection of simulation vs. hardware mode
- Error handling for sensor reading failures
- Temperature unit conversion methods
- Comprehensive metadata including sensor type and last readings
## Hardware Requirements
- ESP32 microcontroller
- DHT22/AM2302 temperature and humidity sensor
- MicroPython firmware installed on the ESP32
- Appropriate wiring:
- Connect VCC to 3.3V or 5V power supply
- Connect GND to ground
- Connect DATA to a GPIO pin (default is GPIO4)
- A 10K pull-up resistor between VCC and DATA is recommended
## Software Dependencies
- MicroPython with `dht` and `machine` modules
- For simulation mode, only the standard Python libraries are required
## Usage
### Basic Usage
```python
from src.esp_sensors.dht22 import DHT22Sensor
# Initialize the sensor
sensor = DHT22Sensor("living_room", 4) # name, GPIO pin
# Read temperature
temperature = sensor.read()
print(f"Temperature: {temperature}°C")
# Read humidity
humidity = sensor.read_humidity()
print(f"Humidity: {humidity}%")
# Get temperature in Fahrenheit
fahrenheit = sensor.to_fahrenheit()
print(f"Temperature: {fahrenheit}°F")
```
### Advanced Usage
```python
from src.esp_sensors.dht22 import DHT22Sensor
import time
# Initialize with custom parameters
sensor = DHT22Sensor(
name="outdoor",
pin=5,
interval=30, # Read every 30 seconds
unit="F" # Use Fahrenheit
)
# Continuous reading
try:
while True:
temp = sensor.read()
humidity = sensor.read_humidity()
# Get metadata
metadata = sensor.get_metadata()
print(f"Sensor: {metadata['name']}")
print(f"Temperature: {temp}°F ({sensor.to_celsius()}°C)")
print(f"Humidity: {humidity}%")
time.sleep(metadata['interval'])
except KeyboardInterrupt:
print("Monitoring stopped")
```
## API Reference
### Class: DHT22Sensor
Extends the base `Sensor` class to provide DHT22-specific functionality.
#### Constructor
```python
DHT22Sensor(name: str, pin: int, interval: int = 60, unit: str = "C")
```
- **name**: A string identifier for the sensor
- **pin**: The GPIO pin number the sensor is connected to
- **interval**: Reading interval in seconds (default: 60)
- **unit**: Temperature unit, either "C" for Celsius or "F" for Fahrenheit (default: "C")
#### Methods
- **read()**: Reads the current temperature and updates humidity
- **read_humidity()**: Returns the current humidity reading
- **to_fahrenheit()**: Converts the last reading to Fahrenheit if it was in Celsius
- **to_celsius()**: Converts the last reading to Celsius if it was in Fahrenheit
- **get_metadata()**: Returns a dictionary with sensor information including temperature unit and humidity
## Example
See the `examples/dht22_example.py` file for a complete example of how to use the DHT22 sensor with an ESP32.
## Troubleshooting
- **No readings or errors**: Check your wiring and ensure the DHT22 is properly connected
- **Inconsistent readings**: Make sure you have a pull-up resistor between VCC and DATA
- **ImportError**: Ensure you're running on MicroPython with the required modules
- **ValueError**: Check that you're using a valid temperature unit ("C" or "F")
## License
This implementation is provided under the same license as the main project.

105
examples/dht22_example.py Normal file
View File

@@ -0,0 +1,105 @@
"""
Example script for using the DHT22 sensor with an ESP32.
This script demonstrates how to initialize and read from a DHT22 sensor
connected to an ESP32 microcontroller.
Usage:
- Upload this script to your ESP32 running MicroPython
- Connect the DHT22 sensor to the specified GPIO pin
- The script will read temperature and humidity at the specified interval
"""
import time
import sys
# Check if running on MicroPython
if sys.implementation.name == 'micropython':
from src.esp_sensors.dht22 import DHT22Sensor
# Configuration
SENSOR_NAME = "living_room"
SENSOR_PIN = 4 # GPIO pin where DHT22 is connected
READ_INTERVAL = 5 # seconds between readings
def main():
print(f"Initializing DHT22 sensor on pin {SENSOR_PIN}")
# Initialize the sensor
sensor = DHT22Sensor(SENSOR_NAME, SENSOR_PIN, READ_INTERVAL)
print("Starting sensor readings. Press Ctrl+C to stop.")
try:
while True:
# Read temperature
temperature = sensor.read()
# Read humidity
humidity = sensor.read_humidity()
# Get the current timestamp
timestamp = time.time()
# Print readings
print(f"Time: {timestamp}")
print(f"Temperature: {temperature}°C ({sensor.to_fahrenheit()}°F)")
print(f"Humidity: {humidity}%")
print("-" * 30)
# Wait for the next reading
time.sleep(READ_INTERVAL)
except KeyboardInterrupt:
print("Sensor readings stopped.")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
else:
print("This script is designed to run on MicroPython on an ESP32.")
print("Running in simulation mode for demonstration purposes.")
# Import for simulation mode
from src.esp_sensors.dht22 import DHT22Sensor
# Configuration
SENSOR_NAME = "simulation"
SENSOR_PIN = 4
READ_INTERVAL = 2 # shorter interval for demonstration
def main():
print(f"Initializing DHT22 sensor simulation")
# Initialize the sensor
sensor = DHT22Sensor(SENSOR_NAME, SENSOR_PIN, READ_INTERVAL)
print("Starting simulated sensor readings. Press Ctrl+C to stop.")
try:
for _ in range(5): # Just do 5 readings for the simulation
# Read temperature
temperature = sensor.read()
# Read humidity
humidity = sensor.read_humidity()
# Get the current timestamp
timestamp = time.time()
# Print readings
print(f"Time: {timestamp}")
print(f"Temperature: {temperature}°C ({sensor.to_fahrenheit()}°F)")
print(f"Humidity: {humidity}%")
print("-" * 30)
# Wait for the next reading
time.sleep(READ_INTERVAL)
print("Simulation complete.")
except KeyboardInterrupt:
print("Sensor readings stopped.")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()

133
src/esp_sensors/dht22.py Normal file
View File

@@ -0,0 +1,133 @@
"""
DHT22 temperature and humidity sensor module for ESP32.
"""
import time
try:
import dht
from machine import Pin
SIMULATION = False
except ImportError:
import random
SIMULATION = True
from .sensor import Sensor
class DHT22Sensor(Sensor):
"""DHT22 temperature and humidity sensor implementation."""
def __init__(self, name: str, pin: int, interval: int = 60, unit: str = "C"):
"""
Initialize a new DHT22 sensor.
Args:
name: The name of the sensor
pin: The GPIO pin number the sensor is connected to
interval: Reading interval in seconds (default: 60)
unit: Temperature unit, either "C" for Celsius or "F" for Fahrenheit (default: "C")
"""
super().__init__(name, pin, interval)
if unit not in ["C", "F"]:
raise ValueError("Unit must be either 'C' or 'F'")
self.unit = unit
self._last_humidity = None
# Initialize the sensor if not in simulation mode
if not SIMULATION:
self._sensor = dht.DHT22(Pin(pin))
def read(self) -> float:
"""
Read the current temperature.
Returns:
The temperature reading as a float
"""
if SIMULATION:
# Simulate temperature reading
if self.unit == "C":
self._last_reading = round(random.uniform(15.0, 30.0), 1)
else:
self._last_reading = round(random.uniform(59.0, 86.0), 1)
# Simulate humidity reading (between 30% and 90%)
self._last_humidity = round(random.uniform(30.0, 90.0), 1)
else:
# Actual hardware reading
try:
self._sensor.measure()
temp = self._sensor.temperature()
# Convert to Fahrenheit if needed
if self.unit == "F":
temp = (temp * 9 / 5) + 32
self._last_reading = round(temp, 1)
self._last_humidity = round(self._sensor.humidity(), 1)
except Exception as e:
print(f"Error reading DHT22 sensor: {e}")
# Return last reading if available, otherwise default value
if self._last_reading is None:
self._last_reading = 0.0
if self._last_humidity is None:
self._last_humidity = 0.0
return self._last_reading
def read_humidity(self) -> float:
"""
Read the current humidity.
Returns:
The humidity reading as a float (percentage)
"""
# If we haven't read yet, read only humidity
if self._last_humidity is None:
if SIMULATION:
# Simulate humidity reading (between 30% and 90%)
self._last_humidity = round(random.uniform(30.0, 90.0), 1)
else:
# Actual hardware reading
try:
self._sensor.measure()
self._last_humidity = round(self._sensor.humidity(), 1)
except Exception as e:
print(f"Error reading DHT22 humidity: {e}")
# Return default value if no previous reading
self._last_humidity = 0.0
return self._last_humidity
def get_metadata(self):
"""
Get sensor metadata including temperature unit and humidity.
Returns:
A dictionary containing sensor metadata
"""
metadata = super().get_metadata()
metadata["unit"] = self.unit
metadata["last_humidity"] = self._last_humidity
metadata["type"] = "DHT22"
return metadata
def to_fahrenheit(self) -> float | None:
"""
Convert the last reading to Fahrenheit if it was in Celsius.
Returns:
The temperature in Fahrenheit
"""
if self.unit == "F" or self._last_reading is None:
return self._last_reading
return (self._last_reading * 9 / 5) + 32
def to_celsius(self) -> float | None:
"""
Convert the last reading to Celsius if it was in Fahrenheit.
Returns:
The temperature in Celsius
"""
if self.unit == "C" or self._last_reading is None:
return self._last_reading
return (self._last_reading - 32) * 5 / 9

100
tests/test_dht22_sensor.py Normal file
View File

@@ -0,0 +1,100 @@
"""
Tests for the DHT22 sensor module.
"""
import pytest
from src.esp_sensors.dht22 import DHT22Sensor
def test_dht22_sensor_initialization():
"""Test that a DHT22 sensor can be initialized with valid parameters."""
sensor = DHT22Sensor("test_sensor", 5, 30, "C")
assert sensor.name == "test_sensor"
assert sensor.pin == 5
assert sensor.interval == 30
assert sensor.unit == "C"
assert sensor._last_humidity is None
def test_dht22_sensor_invalid_unit():
"""Test that initializing with an invalid unit raises a ValueError."""
with pytest.raises(ValueError):
DHT22Sensor("test_sensor", 5, 30, "K")
def test_dht22_sensor_read_temperature():
"""Test that reading temperature from the sensor returns a float value."""
sensor = DHT22Sensor("test_sensor", 5)
reading = sensor.read()
assert isinstance(reading, float)
# For Celsius, the reading should be between 15.0 and 30.0
assert 15.0 <= reading <= 30.0
def test_dht22_sensor_read_humidity():
"""Test that reading humidity from the sensor returns a float value."""
sensor = DHT22Sensor("test_sensor", 5)
humidity = sensor.read_humidity()
assert isinstance(humidity, float)
# Humidity should be between 30.0% and 90.0%
assert 30.0 <= humidity <= 90.0
def test_dht22_sensor_fahrenheit():
"""Test that a sensor initialized with Fahrenheit returns appropriate values."""
sensor = DHT22Sensor("test_sensor", 5, unit="F")
reading = sensor.read()
assert isinstance(reading, float)
# For Fahrenheit, the reading should be between 59.0 and 86.0
assert 59.0 <= reading <= 86.0
def test_dht22_temperature_conversion():
"""Test temperature conversion methods."""
# Test Celsius to Fahrenheit
c_sensor = DHT22Sensor("celsius_sensor", 5, unit="C")
c_sensor._last_reading = 20.0 # Manually set for testing
f_value = c_sensor.to_fahrenheit()
assert f_value == 68.0 # 20°C = 68°F
# Test Fahrenheit to Celsius
f_sensor = DHT22Sensor("fahrenheit_sensor", 5, unit="F")
f_sensor._last_reading = 68.0 # Manually set for testing
c_value = f_sensor.to_celsius()
assert c_value == 20.0 # 68°F = 20°C
def test_dht22_metadata():
"""Test that metadata includes the temperature unit, humidity, and type."""
sensor = DHT22Sensor("test_sensor", 5, unit="C")
metadata = sensor.get_metadata()
assert metadata["name"] == "test_sensor"
assert metadata["pin"] == 5
assert metadata["unit"] == "C"
assert metadata["last_reading"] is None # No reading yet
assert metadata["last_humidity"] is None # No reading yet
assert metadata["type"] == "DHT22"
# After a reading
sensor.read()
metadata = sensor.get_metadata()
assert metadata["last_reading"] is not None
assert metadata["last_humidity"] is not None
def test_dht22_read_updates_both_values():
"""Test that reading temperature also updates humidity."""
sensor = DHT22Sensor("test_sensor", 5)
assert sensor._last_humidity is None
# Reading temperature should also update humidity
sensor.read()
assert sensor._last_humidity is not None
# Reset humidity to test read_humidity
old_temp = sensor._last_reading
sensor._last_humidity = None
# Reading humidity should not change temperature
humidity = sensor.read_humidity()
assert sensor._last_reading == old_temp
assert humidity is not None