mirror of
https://github.com/OMGeeky/homecontrol.esp-sensors.git
synced 2026-02-23 15:49:52 +01:00
dht22 implementation
This commit is contained in:
116
README.md
Normal file
116
README.md
Normal 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
127
docs/dht22_sensor.md
Normal 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
105
examples/dht22_example.py
Normal 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
133
src/esp_sensors/dht22.py
Normal 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
100
tests/test_dht22_sensor.py
Normal 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
|
||||
Reference in New Issue
Block a user