commit 236d5e4a8c5ce29bbb94b8142fadd1d939926f5b Author: Andrey Aleksandrov Date: Tue Dec 30 21:48:48 2025 +0200 Initial commit diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8625ef8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v1.0.0] - 2024-12-30 + +### Added + +- Repository diff --git a/README.md b/README.md new file mode 100644 index 0000000..0748159 --- /dev/null +++ b/README.md @@ -0,0 +1,134 @@ +# ESP32 Custom Libraries Collection + +A collection of custom libraries designed for ESP32 development with ESP-IDF framework. These libraries are optimized for IoT sensor projects and provide reliable, reusable components. + +## Libraries Overview + +### 🌡️ DHT22 Sensor (`dht22_sensor`) + +- **Version**: 1.0.0 +- **Description**: Custom DHT22/AM2302 sensor library with bit-banging implementation +- **Features**: Temperature and humidity reading with robust timing control +- **Use Case**: Environmental monitoring projects + +### Method 1: Git + +```bash +cd your_project_directory +mkdir dht22 +git clone https://home.arcoa.eu:8413/esp32libs/dht22_sensor.git +``` + +### Method 2: Manual Copy + +1. Clone or download this repository +2. Copy the desired library folders to your project's `lib/` directory +3. Include the headers in your main code + +### Method 3: PlatformIO Library + +Each library contains a `library.json` file for PlatformIO compatibility. + +## Usage Example + +```c +#include "dht22_sensor.h" +#include "wifi_manager.h" +#include "mqtt_manager.h" +#include "led_manager.h" + +void app_main(void) { + // Initialize WiFi + wifi_manager_config_t wifi_config = { + .ssid = "YourSSID", + .password = "YourPassword" + }; + wifi_manager_init(&wifi_config); + + // Initialize MQTT + mqtt_manager_config_t mqtt_config = { + .broker_url = "mqtt://your-broker.com", + .client_id = "esp32_sensor" + }; + mqtt_manager_init(&mqtt_config); + + // Initialize DHT22 sensor + dht22_init(GPIO_NUM_4); + + // Initialize LED for status indication + led_manager_init(GPIO_NUM_8, 1); + + // Your application logic here + while (1) { + float temperature, humidity; + if (dht22_read(&temperature, &humidity) == ESP_OK) { + mqtt_publish_sensor_data(temperature, humidity); + led_manager_set_color(0, 255, 0); // Green for success + } else { + led_manager_set_color(255, 0, 0); // Red for error + } + + vTaskDelay(pdMS_TO_TICKS(30000)); // 30 second interval + } +} +``` + +## Library Dependencies + +``` +mqtt_manager → (none) +``` + +## Configuration + +Library includes configuration options through header files. Check individual library documentation for specific configuration parameters. + +### Common GPIO Assignments + +- **DHT22**: Any GPIO pin (recommended: GPIO 4) +- **LED Strip**: Any GPIO pin (recommended: GPIO 8) +- **Built-in LED**: GPIO 2 (ESP32-C6) + +## Compatibility + +- **Framework**: ESP-IDF +- **Platforms**: ESP32, ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C6 +- **Tested**: ESP32-C6 DevKit +- **License**: MIT + +## Project Structure + +``` +MyESP32Libs/ +├── README.md +├── CHANGELOG.md +├── dht22_sensor.c +├── dht22_sensor.h +├── README.md +├── CHANGELOG.md +├── library.json +``` + +## Contributing + +1. Fork this repository +2. Create a feature branch (`git checkout -b feature/new-library`) +3. Commit your changes (`git commit -am 'Add new library'`) +4. Push to the branch (`git push origin feature/new-library`) +5. Create a Pull Request + +## Development Notes + +⚠️ **VSCode Include Errors**: If you see `cannot open source file "esp_err.h"` errors in VSCode, this is expected for standalone library development. See [DEVELOPMENT.md](DEVELOPMENT.md) for solutions. + +## License + +This project is licensed under the MIT License - see individual library.json files for details. + +## Support + +For issues and questions: + +- Create an issue in this repository +- Check individual library headers for API documentation +- Refer to ESP-IDF documentation for framework-specific details diff --git a/dht22_sensor.c b/dht22_sensor.c new file mode 100644 index 0000000..81e296b --- /dev/null +++ b/dht22_sensor.c @@ -0,0 +1,307 @@ +#include "dht22_sensor.h" +#include "esp_log.h" +#include "esp_rom_sys.h" +#include "freertos/FreeRTOS.h" +#include "freertos/portmacro.h" +#include + +static const char *TAG = "DHT22_SENSOR"; + +// Default DHT22 timing constants (microseconds) +#define DHT22_DEFAULT_START_SIGNAL_US 18000 // 18ms start signal +#define DHT22_DEFAULT_RESPONSE_TIMEOUT_US 500 // 500us timeout for response +#define DHT22_DEFAULT_DATA_TIMEOUT_US 150 // 150us timeout for data bits +#define DHT22_DEFAULT_BIT_THRESHOLD_US 40 // Threshold for 0/1 detection + +// Global configuration +static dht22_config_t current_config = {0}; +static bool is_initialized = false; + +// Internal function to read from DHT22 +static dht22_result_t dht22_read_internal(int gpio_pin, float *temperature, float *humidity, const dht22_config_t *config); + +esp_err_t dht22_init(int gpio_pin) +{ + dht22_config_t default_config = { + .gpio_pin = gpio_pin, + .start_signal_us = DHT22_DEFAULT_START_SIGNAL_US, + .response_timeout_us = DHT22_DEFAULT_RESPONSE_TIMEOUT_US, + .data_timeout_us = DHT22_DEFAULT_DATA_TIMEOUT_US, + .bit_threshold_us = DHT22_DEFAULT_BIT_THRESHOLD_US}; + + return dht22_init_with_config(&default_config); +} + +esp_err_t dht22_init_with_config(const dht22_config_t *config) +{ + if (config == NULL) + { + ESP_LOGE(TAG, "DHT22 config cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + + if (config->gpio_pin < 0) + { + ESP_LOGE(TAG, "Invalid GPIO pin: %d", config->gpio_pin); + return ESP_ERR_INVALID_ARG; + } + + ESP_LOGI(TAG, "Initializing DHT22 on GPIO %d", config->gpio_pin); + + // Store configuration + memcpy(¤t_config, config, sizeof(dht22_config_t)); + is_initialized = true; + + ESP_LOGI(TAG, "DHT22 initialized successfully"); + return ESP_OK; +} + +dht22_result_t dht22_read(float *temperature, float *humidity) +{ + if (!is_initialized) + { + ESP_LOGE(TAG, "DHT22 not initialized"); + return DHT22_TIMEOUT_ERROR; + } + + return dht22_read_internal(current_config.gpio_pin, temperature, humidity, ¤t_config); +} + +dht22_result_t dht22_read_data(dht22_data_t *data) +{ + if (data == NULL) + { + ESP_LOGE(TAG, "DHT22 data pointer cannot be NULL"); + return DHT22_TIMEOUT_ERROR; + } + + return dht22_read(&data->temperature, &data->humidity); +} + +dht22_result_t dht22_read_from_pin(int gpio_pin, float *temperature, float *humidity) +{ + dht22_config_t temp_config = { + .gpio_pin = gpio_pin, + .start_signal_us = DHT22_DEFAULT_START_SIGNAL_US, + .response_timeout_us = DHT22_DEFAULT_RESPONSE_TIMEOUT_US, + .data_timeout_us = DHT22_DEFAULT_DATA_TIMEOUT_US, + .bit_threshold_us = DHT22_DEFAULT_BIT_THRESHOLD_US}; + + return dht22_read_internal(gpio_pin, temperature, humidity, &temp_config); +} + +static dht22_result_t dht22_read_internal(int gpio_pin, float *temperature, float *humidity, const dht22_config_t *config) +{ + if (temperature == NULL || humidity == NULL) + { + ESP_LOGE(TAG, "Temperature and humidity pointers cannot be NULL"); + return DHT22_TIMEOUT_ERROR; + } + + uint8_t data[5] = {0}; + int counter = 0; + + ESP_LOGD(TAG, "Reading DHT22 from GPIO %d", gpio_pin); + + // Disable interrupts during critical timing + portDISABLE_INTERRUPTS(); + + // Configure GPIO + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << gpio_pin), + .mode = GPIO_MODE_OUTPUT_OD, + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + gpio_config(&io_conf); + + // Send start signal + gpio_set_level(gpio_pin, 0); + esp_rom_delay_us(config->start_signal_us); + gpio_set_level(gpio_pin, 1); + esp_rom_delay_us(40); + + // Switch to input mode + io_conf.mode = GPIO_MODE_INPUT; + gpio_config(&io_conf); + + // Wait for DHT22 response (should go low then high) + counter = 0; + while (gpio_get_level(gpio_pin) == 1) + { + esp_rom_delay_us(1); + if (++counter > config->response_timeout_us) + { + portENABLE_INTERRUPTS(); + ESP_LOGD(TAG, "DHT22 timeout waiting for initial response"); + return DHT22_TIMEOUT_ERROR; + } + } + + // Wait for response signal to go high + counter = 0; + while (gpio_get_level(gpio_pin) == 0) + { + esp_rom_delay_us(1); + if (++counter > config->response_timeout_us) + { + portENABLE_INTERRUPTS(); + ESP_LOGD(TAG, "DHT22 timeout waiting for response high"); + return DHT22_TIMEOUT_ERROR; + } + } + + // Wait for response signal to go low (start of data) + counter = 0; + while (gpio_get_level(gpio_pin) == 1) + { + esp_rom_delay_us(1); + if (++counter > config->response_timeout_us) + { + portENABLE_INTERRUPTS(); + ESP_LOGD(TAG, "DHT22 timeout waiting for data start"); + return DHT22_TIMEOUT_ERROR; + } + } + + // Read 40 bits of data + for (int i = 0; i < 40; i++) + { + // Wait for signal to go high + counter = 0; + while (gpio_get_level(gpio_pin) == 0) + { + esp_rom_delay_us(1); + if (++counter > config->data_timeout_us) + { + portENABLE_INTERRUPTS(); + ESP_LOGD(TAG, "DHT22 timeout waiting for bit %d high signal", i); + return DHT22_TIMEOUT_ERROR; + } + } + + // Measure high pulse duration + counter = 0; + while (gpio_get_level(gpio_pin) == 1) + { + esp_rom_delay_us(1); + if (++counter > config->data_timeout_us) + { + portENABLE_INTERRUPTS(); + ESP_LOGD(TAG, "DHT22 timeout during bit %d high pulse", i); + return DHT22_TIMEOUT_ERROR; + } + } + + // DHT22 protocol: '0' = ~26-28us high, '1' = ~70us high + data[i / 8] <<= 1; + if (counter > config->bit_threshold_us) + { + data[i / 8] |= 1; + } + + // Debug first few bits if we're getting all zeros + if (i < 8) + { + ESP_LOGD(TAG, "Bit %d: pulse=%dus, value=%d", i, counter, (counter > config->bit_threshold_us) ? 1 : 0); + } + } + + // Re-enable interrupts + portENABLE_INTERRUPTS(); + + // Verify checksum + uint8_t checksum = data[0] + data[1] + data[2] + data[3]; + + // Debug output for problematic readings + if ((data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) || checksum != data[4]) + { + ESP_LOGD(TAG, "DHT22 raw data: %02X %02X %02X %02X %02X", + data[0], data[1], data[2], data[3], data[4]); + ESP_LOGD(TAG, "Calculated checksum: %02X, Received: %02X", checksum, data[4]); + } + + if (checksum != data[4]) + { + ESP_LOGD(TAG, "DHT22 checksum mismatch"); + return DHT22_CHECKSUM_ERROR; + } + + // Check for all-zero data (sensor not responding properly) + if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) + { + ESP_LOGD(TAG, "DHT22 returned all zeros - sensor may not be connected"); + return DHT22_TIMEOUT_ERROR; // Treat as timeout to trigger retry + } + + // Convert data to temperature and humidity + *humidity = ((data[0] << 8) | data[1]) / 10.0f; + + int temp_raw = (data[2] << 8) | data[3]; + if (temp_raw & 0x8000) + { + *temperature = -(temp_raw & 0x7FFF) / 10.0f; + } + else + { + *temperature = temp_raw / 10.0f; + } + + ESP_LOGD(TAG, "DHT22 read successful: T=%.2f°C, H=%.2f%%", *temperature, *humidity); + return DHT22_OK; +} + +const char *dht22_get_error_string(dht22_result_t result) +{ + switch (result) + { + case DHT22_OK: + return "Success"; + case DHT22_TIMEOUT_ERROR: + return "Timeout error"; + case DHT22_CHECKSUM_ERROR: + return "Checksum error"; + default: + return "Unknown error"; + } +} + +bool dht22_test_connection(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "DHT22 not initialized for connection test"); + return false; + } + + float temp, humid; + dht22_result_t result = dht22_read(&temp, &humid); + + if (result == DHT22_OK) + { + ESP_LOGI(TAG, "DHT22 connection test successful: T=%.2f°C, H=%.2f%%", temp, humid); + return true; + } + else + { + ESP_LOGW(TAG, "DHT22 connection test failed: %s", dht22_get_error_string(result)); + return false; + } +} + +esp_err_t dht22_deinit(void) +{ + if (!is_initialized) + { + ESP_LOGW(TAG, "DHT22 not initialized"); + return ESP_OK; + } + + ESP_LOGI(TAG, "Deinitializing DHT22 sensor"); + is_initialized = false; + memset(¤t_config, 0, sizeof(dht22_config_t)); + + ESP_LOGI(TAG, "DHT22 sensor deinitialized"); + return ESP_OK; +} \ No newline at end of file diff --git a/dht22_sensor.h b/dht22_sensor.h new file mode 100644 index 0000000..a823530 --- /dev/null +++ b/dht22_sensor.h @@ -0,0 +1,112 @@ +#ifndef DHT22_SENSOR_H +#define DHT22_SENSOR_H + +#include "driver/gpio.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * @brief DHT22 result codes + */ + typedef enum + { + DHT22_OK = 0, /**< Reading successful */ + DHT22_TIMEOUT_ERROR = -1, /**< Timeout during communication */ + DHT22_CHECKSUM_ERROR = -2 /**< Checksum verification failed */ + } dht22_result_t; + + /** + * @brief DHT22 sensor configuration + */ + typedef struct + { + int gpio_pin; /**< GPIO pin number where DHT22 is connected */ + uint32_t start_signal_us; /**< Start signal duration in microseconds (default: 18000) */ + uint32_t response_timeout_us; /**< Response timeout in microseconds (default: 500) */ + uint32_t data_timeout_us; /**< Data bit timeout in microseconds (default: 150) */ + uint32_t bit_threshold_us; /**< Threshold for distinguishing 0/1 bits (default: 40) */ + } dht22_config_t; + + /** + * @brief DHT22 sensor data structure + */ + typedef struct + { + float temperature; /**< Temperature in degrees Celsius */ + float humidity; /**< Relative humidity percentage */ + } dht22_data_t; + + /** + * @brief Initialize DHT22 sensor with default configuration + * + * @param gpio_pin GPIO pin number where DHT22 is connected + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t dht22_init(int gpio_pin); + + /** + * @brief Initialize DHT22 sensor with custom configuration + * + * @param config DHT22 configuration parameters + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t dht22_init_with_config(const dht22_config_t *config); + + /** + * @brief Read temperature and humidity from DHT22 sensor + * + * @param temperature Pointer to store temperature value (in Celsius) + * @param humidity Pointer to store humidity value (in percentage) + * @return dht22_result_t DHT22_OK on success, error code on failure + */ + dht22_result_t dht22_read(float *temperature, float *humidity); + + /** + * @brief Read temperature and humidity into data structure + * + * @param data Pointer to DHT22 data structure to fill + * @return dht22_result_t DHT22_OK on success, error code on failure + */ + dht22_result_t dht22_read_data(dht22_data_t *data); + + /** + * @brief Read from specific GPIO pin (for multiple sensors) + * + * @param gpio_pin GPIO pin number + * @param temperature Pointer to store temperature value + * @param humidity Pointer to store humidity value + * @return dht22_result_t DHT22_OK on success, error code on failure + */ + dht22_result_t dht22_read_from_pin(int gpio_pin, float *temperature, float *humidity); + + /** + * @brief Get last error message as string + * + * @param result DHT22 result code + * @return const char* Human-readable error message + */ + const char *dht22_get_error_string(dht22_result_t result); + + /** + * @brief Check if DHT22 sensor is properly connected and responding + * + * @return true if sensor responds correctly, false otherwise + */ + bool dht22_test_connection(void); + + /** + * @brief Deinitialize DHT22 sensor + * + * @return esp_err_t ESP_OK on success, error code on failure + */ + esp_err_t dht22_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif // DHT22_SENSOR_H \ No newline at end of file diff --git a/library.json b/library.json new file mode 100644 index 0000000..ff8822d --- /dev/null +++ b/library.json @@ -0,0 +1,16 @@ +{ + "name": "dht22_sensor", + "version": "1.0.0", + "description": "Custom DHT22 sensor library with bit-banging implementation for ESP32", + "keywords": "dht22, am2302, temperature, humidity, sensor, esp32, bitbang", + "authors": { + "name": "ESP32C6-DHT22 Project" + }, + "license": "MIT", + "frameworks": [ + "espidf" + ], + "platforms": [ + "espressif32" + ] +} \ No newline at end of file