feat!: main structure of handle changed to double pointer
This commit is contained in:
1 parent
e8c79cf078
commit
e534465f8c
8 files changed
+210
-277
No files matched your search
Binary file not shown.
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
1. Support of AHT10/AHT15/AHT20/AHT21/AHT25/AHT30.
|
1. Support of AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40.
|
||||||
2. Support some sensors on one device with [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a).
|
2. Support some sensors on one device with [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a).
|
||||||
|
|
||||||
## Attention
|
## Attention
|
||||||
@@ -41,109 +41,6 @@ In the application, add the component:
|
|||||||
#include "zh_aht.h"
|
#include "zh_aht.h"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Examples
|
||||||
|
|
||||||
Reading the sensor:
|
See Wiki [EN](WIKI_EN.md#usage-examples) | [RU](WIKI_RU.md#примеры-использования)
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_aht.h"
|
|
||||||
|
|
||||||
#define I2C_PORT (I2C_NUM_MAX - 1)
|
|
||||||
|
|
||||||
zh_aht_handle_t aht_handle = {0};
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_aht", ESP_LOG_ERROR);
|
|
||||||
i2c_master_bus_config_t i2c_bus_config = {
|
|
||||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
|
||||||
.i2c_port = I2C_PORT,
|
|
||||||
.scl_io_num = GPIO_NUM_22,
|
|
||||||
.sda_io_num = GPIO_NUM_21,
|
|
||||||
.glitch_ignore_cnt = 7,
|
|
||||||
.flags.enable_internal_pullup = true,
|
|
||||||
};
|
|
||||||
i2c_master_bus_handle_t i2c_bus_handle = NULL;
|
|
||||||
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
|
|
||||||
zh_aht_init_config_t config = ZH_AHT_INIT_CONFIG_DEFAULT();
|
|
||||||
config.i2c_handle = i2c_bus_handle;
|
|
||||||
zh_aht_init(&config, &aht_handle);
|
|
||||||
float humidity = 0.0;
|
|
||||||
float temperature = 0.0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
zh_aht_read(&aht_handle, &humidity, &temperature);
|
|
||||||
printf("Humidity %0.2f\n", humidity);
|
|
||||||
printf("Temperature %0.2f\n", temperature);
|
|
||||||
const zh_aht_stats_t *stats = zh_aht_get_stats();
|
|
||||||
printf("Number of i2c driver error: %ld.\n", stats->i2c_driver_error);
|
|
||||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3 sensor on one device:
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "zh_pca9548a.h"
|
|
||||||
#include "zh_aht.h"
|
|
||||||
|
|
||||||
#define I2C_PORT (I2C_NUM_MAX - 1)
|
|
||||||
|
|
||||||
zh_pca9548a_handle_t pca9548a_handle = {0};
|
|
||||||
zh_aht_handle_t aht_handle_chan_0 = {0};
|
|
||||||
zh_aht_handle_t aht_handle_chan_1 = {0};
|
|
||||||
zh_aht_handle_t aht_handle_chan_2 = {0};
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
esp_log_level_set("zh_pca9548a", ESP_LOG_ERROR);
|
|
||||||
esp_log_level_set("zh_aht", ESP_LOG_ERROR);
|
|
||||||
i2c_master_bus_config_t i2c_bus_config = {
|
|
||||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
|
||||||
.i2c_port = I2C_PORT,
|
|
||||||
.scl_io_num = GPIO_NUM_22,
|
|
||||||
.sda_io_num = GPIO_NUM_21,
|
|
||||||
.glitch_ignore_cnt = 7,
|
|
||||||
.flags.enable_internal_pullup = true,
|
|
||||||
};
|
|
||||||
i2c_master_bus_handle_t i2c_bus_handle = NULL;
|
|
||||||
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
|
|
||||||
zh_pca9548a_init_config_t config = ZH_PCA9548A_INIT_CONFIG_DEFAULT();
|
|
||||||
config.i2c_handle = i2c_bus_handle;
|
|
||||||
config.i2c_address = 0x70;
|
|
||||||
zh_pca9548a_init(&config, &pca9548a_handle);
|
|
||||||
zh_aht_init_config_t aht_config = ZH_AHT_INIT_CONFIG_DEFAULT();
|
|
||||||
aht_config.i2c_handle = i2c_bus_handle;
|
|
||||||
zh_pca9548a_set(&pca9548a_handle, ZH_PCA9548A_CHAN_NUM_0);
|
|
||||||
zh_aht_init(&aht_config, &aht_handle_chan_0);
|
|
||||||
zh_pca9548a_set(&pca9548a_handle, ZH_PCA9548A_CHAN_NUM_1);
|
|
||||||
zh_aht_init(&aht_config, &aht_handle_chan_1);
|
|
||||||
zh_pca9548a_set(&pca9548a_handle, ZH_PCA9548A_CHAN_NUM_2);
|
|
||||||
zh_aht_init(&aht_config, &aht_handle_chan_2);
|
|
||||||
float humidity = 0.0;
|
|
||||||
float temperature = 0.0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
zh_pca9548a_set(&pca9548a_handle, ZH_PCA9548A_CHAN_NUM_0);
|
|
||||||
zh_aht_read(&aht_handle_chan_0, &humidity, &temperature);
|
|
||||||
printf("Sensor 1. Humidity %0.2f\n", humidity);
|
|
||||||
printf("Sensor 1. Temperature %0.2f\n", temperature);
|
|
||||||
humidity = 0.0;
|
|
||||||
temperature = 0.0;
|
|
||||||
zh_pca9548a_set(&pca9548a_handle, ZH_PCA9548A_CHAN_NUM_1);
|
|
||||||
zh_aht_read(&aht_handle_chan_1, &humidity, &temperature);
|
|
||||||
printf("Sensor 2. Humidity %0.2f\n", humidity);
|
|
||||||
printf("Sensor 2. Temperature %0.2f\n", temperature);
|
|
||||||
humidity = 0.0;
|
|
||||||
temperature = 0.0;
|
|
||||||
zh_pca9548a_set(&pca9548a_handle, ZH_PCA9548A_CHAN_NUM_2);
|
|
||||||
zh_aht_read(&aht_handle_chan_2, &humidity, &temperature);
|
|
||||||
printf("Sensor 3. Humidity %0.2f\n", humidity);
|
|
||||||
printf("Sensor 3. Temperature %0.2f\n", temperature);
|
|
||||||
humidity = 0.0;
|
|
||||||
temperature = 0.0;
|
|
||||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
+38
-47
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`zh_aht` is a lightweight ESP-IDF component for AHT10/AHT15/AHT20/AHT21/AHT25/AHT30 humidity and temperature sensors. It provides a simple API to read humidity values from 0 to 100% and temperature values from -40 to +85°C. The component supports multiple sensors on a single I2C bus using the [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a) I2C multiplexer.
|
`zh_aht` is a lightweight ESP-IDF component for AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40 humidity and temperature sensors. It provides a simple API to read humidity values from 0 to 100% and temperature values from -40 to +85°C. The component supports multiple sensors on a single I2C bus using the [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a) I2C multiplexer.
|
||||||
|
|
||||||
The component is designed specifically for ESP32 microcontrollers and uses ESP-IDF v5.0+ I2C driver API.
|
The component is designed specifically for ESP32 microcontrollers and uses ESP-IDF v5.0+ I2C driver API.
|
||||||
|
|
||||||
@@ -26,8 +26,8 @@ The component is designed specifically for ESP32 microcontrollers and uses ESP-I
|
|||||||
|
|
||||||
1. **Humidity and Temperature Measurement**: Reads humidity from 0 to 100% and temperature from -40 to +85°C
|
1. **Humidity and Temperature Measurement**: Reads humidity from 0 to 100% and temperature from -40 to +85°C
|
||||||
2. **I2C Interface**: Uses standard I2C protocol (400 kHz max frequency)
|
2. **I2C Interface**: Uses standard I2C protocol (400 kHz max frequency)
|
||||||
3. **Configurable I2C Address**: Supports both 0x38 and 0x39 addresses
|
3. **Configurable I2C Address**: Supports 0x38, 0x39 and 0x44 addresses
|
||||||
4. **Multiple Model Support**: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30
|
4. **Multiple Model Support**: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40
|
||||||
5. **Error Statistics**: Built-in error counter for I2C driver errors
|
5. **Error Statistics**: Built-in error counter for I2C driver errors
|
||||||
6. **Low Power**: Works with ESP-IDF power management
|
6. **Low Power**: Works with ESP-IDF power management
|
||||||
7. **Thread-Safe**: Uses ESP-IDF I2C driver (thread-safe)
|
7. **Thread-Safe**: Uses ESP-IDF I2C driver (thread-safe)
|
||||||
@@ -75,13 +75,15 @@ To use multiple AHT sensors on the same I2C bus, also install the [zh_pca9548a](
|
|||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
|
All functions in this library use double pointer (`zh_aht_handle_t **`) for the sensor handler to allow for proper memory management and thread-safe operations.
|
||||||
|
|
||||||
### zh_aht_init_config_t Structure
|
### zh_aht_init_config_t Structure
|
||||||
|
|
||||||
```c
|
```c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
i2c_master_bus_handle_t i2c_handle; // Unique I2C bus handle
|
i2c_master_bus_handle_t i2c_handle; // Unique I2C bus handle
|
||||||
uint8_t i2c_address; // Sensor I2C address (0x38 or 0x39)
|
uint8_t i2c_address; // Sensor I2C address (0x38, 0x39, or 0x44)
|
||||||
uint32_t i2c_frequency; // Sensor I2C frequency (max 400000 Hz)
|
uint32_t i2c_frequency; // Sensor I2C frequency (max 400000 Hz)
|
||||||
} zh_aht_init_config_t;
|
} zh_aht_init_config_t;
|
||||||
```
|
```
|
||||||
@@ -95,13 +97,13 @@ Use `ZH_AHT_INIT_CONFIG_DEFAULT()` macro to initialize with default values:
|
|||||||
|
|
||||||
### zh_aht_handle_t Structure
|
### zh_aht_handle_t Structure
|
||||||
|
|
||||||
```c
|
The structure is declared as `typedef struct _zh_aht_handle_t zh_aht_handle_t;` and encapsulates internal implementation details.
|
||||||
typedef struct
|
|
||||||
{
|
**Fields (internal):**
|
||||||
bool is_initialized; // Sensor initialization flag
|
|
||||||
i2c_master_dev_handle_t dev_handle; // Unique I2C device handle
|
| Field | Type | Description |
|
||||||
} zh_aht_handle_t;
|
|-------|------|-------------|
|
||||||
```
|
| `i2c_master_dev_handle_t` | `dev_handle` | Pointer to I2C device handle. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,18 +125,21 @@ Initializes the AHT sensor.
|
|||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `config` - Pointer to AHT initialization configuration structure
|
- `config` - Pointer to AHT initialization configuration structure
|
||||||
- `handle` - Pointer to unique AHT handle
|
- `handle` - Double pointer to unique AHT handle (`zh_aht_handle_t **`). If the pointer is NULL, memory will be allocated.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
- `ESP_OK` - Success
|
||||||
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL config or handle)
|
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL config or handle)
|
||||||
- `ESP_FAIL` - Initialization failed (configuration check or I2C device addition)
|
- `ESP_ERR_INVALID_STATE` - Sensor is already initialized
|
||||||
|
- `ESP_ERR_NO_MEM` - Memory allocation failed
|
||||||
|
- `ESP_FAIL` - Initialization I2C device failed
|
||||||
|
- `ESP_ERR_NOT_FOUND` - Sensor did not respond
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
```c
|
```c
|
||||||
zh_aht_handle_t aht_handle = {0};
|
zh_aht_handle_t *aht_handle = NULL;
|
||||||
zh_aht_init_config_t config = ZH_AHT_INIT_CONFIG_DEFAULT();
|
zh_aht_init_config_t config = ZH_AHT_INIT_CONFIG_DEFAULT();
|
||||||
config.i2c_handle = i2c_bus_handle;
|
config.i2c_handle = i2c_bus_handle;
|
||||||
zh_aht_init(&config, &aht_handle);
|
zh_aht_init(&config, &aht_handle);
|
||||||
@@ -144,17 +149,16 @@ zh_aht_init(&config, &aht_handle);
|
|||||||
|
|
||||||
### zh_aht_deinit()
|
### zh_aht_deinit()
|
||||||
|
|
||||||
Deinitializes the AHT sensor and removes it from the I2C bus.
|
Deinitializes the AHT sensor and removes it from the I2C bus. Memory for handle is automatically freed and the pointer is set to NULL.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `handle` - Pointer to unique AHT handle
|
- `handle` - Double pointer to unique AHT handle (`zh_aht_handle_t **`). Must not be NULL.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
- `ESP_OK` - Success
|
||||||
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
|
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle pointer)
|
||||||
- `ESP_ERR_INVALID_STATE` - Sensor not initialized
|
|
||||||
- `ESP_FAIL` - I2C device removal failed
|
- `ESP_FAIL` - I2C device removal failed
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -165,18 +169,17 @@ Reads humidity and temperature values from the sensor.
|
|||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `handle` - Pointer to unique AHT handle
|
- `handle` - Double pointer to unique AHT handle (`zh_aht_handle_t **`). Must not be NULL.
|
||||||
- `humidity` - Pointer to store humidity value (in %)
|
- `humidity` - Pointer to store humidity value (in %)
|
||||||
- `temperature` - Pointer to store temperature value (in °C)
|
- `temperature` - Pointer to store temperature value (in °C)
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
- `ESP_OK` - Success
|
||||||
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, humidity or temperature)
|
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle pointer or humidity pointer or temperature pointer)
|
||||||
- `ESP_ERR_NOT_FOUND` - Sensor not initialized
|
- `ESP_FAIL` - I2C communication error
|
||||||
- `ESP_ERR_TIMEOUT` - Timeout waiting for data ready
|
- `ESP_ERR_TIMEOUT` - Timeout waiting for data ready
|
||||||
- `ESP_ERR_INVALID_CRC` - Invalid CRC checksum
|
- `ESP_ERR_INVALID_CRC` - Invalid CRC checksum
|
||||||
- `ESP_FAIL` - I2C communication error
|
|
||||||
|
|
||||||
**Note:** The function performs measurement and waits ~80ms for data ready.
|
**Note:** The function performs measurement and waits ~80ms for data ready.
|
||||||
|
|
||||||
@@ -188,13 +191,12 @@ Resets the AHT sensor.
|
|||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
- `handle` - Pointer to unique AHT handle
|
- `handle` - Double pointer to unique AHT handle (`zh_aht_handle_t **`). Must not be NULL.
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
- `ESP_OK` - Success
|
- `ESP_OK` - Success
|
||||||
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
|
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle pointer)
|
||||||
- `ESP_ERR_NOT_FOUND` - Sensor not initialized
|
|
||||||
- `ESP_FAIL` - I2C communication error
|
- `ESP_FAIL` - I2C communication error
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -207,25 +209,12 @@ Gets error statistics since last reset.
|
|||||||
|
|
||||||
- Pointer to the statistics structure
|
- Pointer to the statistics structure
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
const zh_aht_stats_t *stats = zh_aht_get_stats();
|
|
||||||
printf("I2C errors: %ld\n", stats->i2c_driver_error);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### zh_aht_reset_stats()
|
### zh_aht_reset_stats()
|
||||||
|
|
||||||
Resets error statistics counter.
|
Resets error statistics counter.
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
zh_aht_reset_stats();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
@@ -237,7 +226,7 @@ zh_aht_reset_stats();
|
|||||||
|
|
||||||
#define I2C_PORT (I2C_NUM_MAX - 1)
|
#define I2C_PORT (I2C_NUM_MAX - 1)
|
||||||
|
|
||||||
zh_aht_handle_t aht_handle = {0};
|
zh_aht_handle_t *aht_handle = NULL;
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
@@ -280,9 +269,9 @@ void app_main(void)
|
|||||||
#define I2C_PORT (I2C_NUM_MAX - 1)
|
#define I2C_PORT (I2C_NUM_MAX - 1)
|
||||||
|
|
||||||
zh_pca9548a_handle_t pca9548a_handle = {0};
|
zh_pca9548a_handle_t pca9548a_handle = {0};
|
||||||
zh_aht_handle_t aht_handle_chan_0 = {0};
|
zh_aht_handle_t *aht_handle_chan_0 = NULL;
|
||||||
zh_aht_handle_t aht_handle_chan_1 = {0};
|
zh_aht_handle_t *aht_handle_chan_1 = NULL;
|
||||||
zh_aht_handle_t aht_handle_chan_2 = {0};
|
zh_aht_handle_t *aht_handle_chan_2 = NULL;
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
@@ -346,10 +335,10 @@ void app_main(void)
|
|||||||
| **Temperature Range** | -40 - +85°C |
|
| **Temperature Range** | -40 - +85°C |
|
||||||
| **Humidity Resolution** | 0.01% |
|
| **Humidity Resolution** | 0.01% |
|
||||||
| **Temperature Resolution** | 0.01°C |
|
| **Temperature Resolution** | 0.01°C |
|
||||||
| **I2C Address** | 0x38, 0x39 |
|
| **I2C Address** | 0x38, 0x39, 0x44 |
|
||||||
| **I2C Frequency** | Up to 400 kHz |
|
| **I2C Frequency** | Up to 400 kHz |
|
||||||
| **Measurement Time** | ~80 ms |
|
| **Measurement Time** | ~80 ms |
|
||||||
| **Supported Models** | AHT10, AHT15, AHT20, AHT21, AHT25, AHT30 |
|
| **Supported Models** | AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40 |
|
||||||
| **ESP-IDF Version** | >= 5.0 |
|
| **ESP-IDF Version** | >= 5.0 |
|
||||||
| **Platform** | ESP32 series |
|
| **Platform** | ESP32 series |
|
||||||
| **Language** | C (C99) |
|
| **Language** | C (C99) |
|
||||||
@@ -362,8 +351,9 @@ void app_main(void)
|
|||||||
|------------|-------------|
|
|------------|-------------|
|
||||||
| `ESP_OK` | Operation successful |
|
| `ESP_OK` | Operation successful |
|
||||||
| `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or invalid configuration) |
|
| `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or invalid configuration) |
|
||||||
| `ESP_ERR_INVALID_STATE` | Sensor not initialized |
|
| `ESP_ERR_INVALID_STATE` | Sensor is already initialized |
|
||||||
| `ESP_ERR_NOT_FOUND` | Sensor not initialized or not responding |
|
| `ESP_ERR_NO_MEM` | Memory allocation failed |
|
||||||
|
| `ESP_ERR_NOT_FOUND` | Sensor did not respond |
|
||||||
| `ESP_ERR_TIMEOUT` | Timeout waiting for data ready |
|
| `ESP_ERR_TIMEOUT` | Timeout waiting for data ready |
|
||||||
| `ESP_ERR_INVALID_CRC` | Invalid CRC checksum |
|
| `ESP_ERR_INVALID_CRC` | Invalid CRC checksum |
|
||||||
| `ESP_FAIL` | General failure (I2C communication error) |
|
| `ESP_FAIL` | General failure (I2C communication error) |
|
||||||
@@ -412,7 +402,8 @@ limitations under the License.
|
|||||||
- **Measurement Time**: The sensor requires ~80ms for each measurement
|
- **Measurement Time**: The sensor requires ~80ms for each measurement
|
||||||
- **I2C_ISR_IRAM_SAFE**: For correct operation, enable `I2C_ISR_IRAM_SAFE` and `I2C_MASTER_ISR_HANDLER_IN_IRAM` in menuconfig
|
- **I2C_ISR_IRAM_SAFE**: For correct operation, enable `I2C_ISR_IRAM_SAFE` and `I2C_MASTER_ISR_HANDLER_IN_IRAM` in menuconfig
|
||||||
- **Thread Safety**: The component uses ESP-IDF I2C driver which is thread-safe
|
- **Thread Safety**: The component uses ESP-IDF I2C driver which is thread-safe
|
||||||
|
- **Memory Management**: All API functions now use double pointers for handle, which allows automatic memory management (freeing on deinitialization, setting to NULL)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Generated for zh_aht v3.4.0*
|
*Generated for zh_aht v4.0.0*
|
||||||
+35
-44
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
## Обзор
|
## Обзор
|
||||||
|
|
||||||
`zh_aht` - это легковесный компонент ESP-IDF для датчиков влажности и температуры AHT10/AHT15/AHT20/AHT21/AHT25/AHT30. Он предоставляет простой API для считывания значений влажности от 0 до 100% и температуры от -40 до +85°C. Компонент поддерживает несколько датчиков на одной шине I2C с использованием I2C мультиплексатора [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a).
|
`zh_aht` - это легковесный компонент ESP-IDF для датчиков влажности и температуры AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40. Он предоставляет простой API для считывания значений влажности от 0 до 100% и температуры от -40 до +85°C. Компонент поддерживает несколько датчиков на одной шине I2C с использованием I2C мультиплексатора [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a).
|
||||||
|
|
||||||
Компонент разработан специально для микроконтроллеров ESP32 и использует API драйвера I2C ESP-IDF v5.0+.
|
Компонент разработан специально для микроконтроллеров ESP32 и использует API драйвера I2C ESP-IDF v5.0+.
|
||||||
|
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
|
|
||||||
1. **Измерение влажности и температуры**: Считывание значений влажности от 0 до 100% и температуры от -40 до +85°C
|
1. **Измерение влажности и температуры**: Считывание значений влажности от 0 до 100% и температуры от -40 до +85°C
|
||||||
2. **Интерфейс I2C**: Использует стандартный протокол I2C (макс. частота 400 кГц)
|
2. **Интерфейс I2C**: Использует стандартный протокол I2C (макс. частота 400 кГц)
|
||||||
3. **Настраиваемый адрес I2C**: Поддерживает адреса 0x38 и 0x39
|
3. **Настраиваемый адрес I2C**: Поддерживает адреса 0x38, 0x39 и 0x44
|
||||||
4. **Поддержка нескольких моделей**: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30
|
4. **Поддержка нескольких моделей**: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40
|
||||||
5. **Статистика ошибок**: Встроенный счетчик ошибок драйвера I2C
|
5. **Статистика ошибок**: Встроенный счетчик ошибок драйвера I2C
|
||||||
6. **Низкое энергопотребление**: Работает с системой управления питанием ESP-IDF
|
6. **Низкое энергопотребление**: Работает с системой управления питанием ESP-IDF
|
||||||
7. **Потокобезопасность**: Использует драйвер I2C ESP-IDF (потокобезопасен)
|
7. **Потокобезопасность**: Использует драйвер I2C ESP-IDF (потокобезопасен)
|
||||||
@@ -75,13 +75,15 @@ I2C_MASTER_ISR_HANDLER_IN_IRAM
|
|||||||
|
|
||||||
## Справочник API
|
## Справочник API
|
||||||
|
|
||||||
|
Все функции в этой библиотеке используют двойной указатель (`zh_aht_handle_t **`) для дескриптора датчика, чтобы обеспечить правильное управление памятью и потокобезопасность.
|
||||||
|
|
||||||
### Структура zh_aht_init_config_t
|
### Структура zh_aht_init_config_t
|
||||||
|
|
||||||
```c
|
```c
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
i2c_master_bus_handle_t i2c_handle; // Уникальный дескриптор шины I2C
|
i2c_master_bus_handle_t i2c_handle; // Уникальный дескриптор шины I2C
|
||||||
uint8_t i2c_address; // Адрес устройства датчика I2C (0x38 или 0x39)
|
uint8_t i2c_address; // Адрес устройства датчика I2C (0x38, 0x39 или 0x44)
|
||||||
uint32_t i2c_frequency; // Частота I2C датчика (макс. 400000 Гц)
|
uint32_t i2c_frequency; // Частота I2C датчика (макс. 400000 Гц)
|
||||||
} zh_aht_init_config_t;
|
} zh_aht_init_config_t;
|
||||||
```
|
```
|
||||||
@@ -95,13 +97,13 @@ typedef struct
|
|||||||
|
|
||||||
### Структура zh_aht_handle_t
|
### Структура zh_aht_handle_t
|
||||||
|
|
||||||
```c
|
Структура объявляется как `typedef struct _zh_aht_handle_t zh_aht_handle_t;` и инкапсулирует детали внутренней реализации.
|
||||||
typedef struct
|
|
||||||
{
|
**Поля (внутренние):**
|
||||||
bool is_initialized; // Флаг инициализации датчика
|
|
||||||
i2c_master_dev_handle_t dev_handle; // Уникальный дескриптор устройства I2C
|
| Поле | Тип | Описание |
|
||||||
} zh_aht_handle_t;
|
|------|-----|----------|
|
||||||
```
|
| `i2c_master_dev_handle_t` | `dev_handle` | Указатель на дескриптор устройства I2C. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,18 +125,21 @@ typedef struct
|
|||||||
**Параметры:**
|
**Параметры:**
|
||||||
|
|
||||||
- `config` - Указатель на структуру конфигурации инициализации AHT
|
- `config` - Указатель на структуру конфигурации инициализации AHT
|
||||||
- `handle` - Указатель на уникальный дескриптор AHT
|
- `handle` - Двойной указатель на уникальный дескриптор AHT (`zh_aht_handle_t **`). Если указатель NULL, память будет выделена.
|
||||||
|
|
||||||
**Возвращает:**
|
**Возвращает:**
|
||||||
|
|
||||||
- `ESP_OK` - Успех
|
- `ESP_OK` - Успех
|
||||||
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL config или handle)
|
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL config или handle)
|
||||||
- `ESP_FAIL` - Ошибка инициализации (проверка конфигурации или добавление устройства I2C)
|
- `ESP_ERR_INVALID_STATE` - Датчик уже инициализирован
|
||||||
|
- `ESP_ERR_NO_MEM` - Ошибка выделения памяти
|
||||||
|
- `ESP_FAIL` - Ошибка инициализации устройства I2C
|
||||||
|
- `ESP_ERR_NOT_FOUND` - Датчик не отвечает
|
||||||
|
|
||||||
**Пример:**
|
**Пример:**
|
||||||
|
|
||||||
```c
|
```c
|
||||||
zh_aht_handle_t aht_handle = {0};
|
zh_aht_handle_t *aht_handle = NULL;
|
||||||
zh_aht_init_config_t config = ZH_AHT_INIT_CONFIG_DEFAULT();
|
zh_aht_init_config_t config = ZH_AHT_INIT_CONFIG_DEFAULT();
|
||||||
config.i2c_handle = i2c_bus_handle;
|
config.i2c_handle = i2c_bus_handle;
|
||||||
zh_aht_init(&config, &aht_handle);
|
zh_aht_init(&config, &aht_handle);
|
||||||
@@ -144,17 +149,16 @@ zh_aht_init(&config, &aht_handle);
|
|||||||
|
|
||||||
### zh_aht_deinit()
|
### zh_aht_deinit()
|
||||||
|
|
||||||
Деинициализирует датчик AHT и удаляет его из шины I2C.
|
Деинициализирует датчик AHT и удаляет его из шины I2C. Память для handle автоматически освобождается, а указатель устанавливается в NULL.
|
||||||
|
|
||||||
**Параметры:**
|
**Параметры:**
|
||||||
|
|
||||||
- `handle` - Указатель на уникальный дескриптор AHT
|
- `handle` - Двойной указатель на уникальный дескриптор AHT (`zh_aht_handle_t **`). Не должен быть NULL.
|
||||||
|
|
||||||
**Возвращает:**
|
**Возвращает:**
|
||||||
|
|
||||||
- `ESP_OK` - Успех
|
- `ESP_OK` - Успех
|
||||||
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
|
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
|
||||||
- `ESP_ERR_INVALID_STATE` - Датчик не инициализирован
|
|
||||||
- `ESP_FAIL` - Ошибка удаления устройства I2C
|
- `ESP_FAIL` - Ошибка удаления устройства I2C
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -165,7 +169,7 @@ zh_aht_init(&config, &aht_handle);
|
|||||||
|
|
||||||
**Параметры:**
|
**Параметры:**
|
||||||
|
|
||||||
- `handle` - Указатель на уникальный дескриптор AHT
|
- `handle` - Двойной указатель на уникальный дескриптор AHT (`zh_aht_handle_t **`). Не должен быть NULL.
|
||||||
- `humidity` - Указатель для хранения значения влажности (в %)
|
- `humidity` - Указатель для хранения значения влажности (в %)
|
||||||
- `temperature` - Указатель для хранения значения температуры (в °C)
|
- `temperature` - Указатель для хранения значения температуры (в °C)
|
||||||
|
|
||||||
@@ -173,10 +177,9 @@ zh_aht_init(&config, &aht_handle);
|
|||||||
|
|
||||||
- `ESP_OK` - Успех
|
- `ESP_OK` - Успех
|
||||||
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, humidity или temperature)
|
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, humidity или temperature)
|
||||||
- `ESP_ERR_NOT_FOUND` - Датчик не инициализирован
|
- `ESP_FAIL` - Ошибка связи I2C
|
||||||
- `ESP_ERR_TIMEOUT` - Превышено время ожидания готовности данных
|
- `ESP_ERR_TIMEOUT` - Превышено время ожидания готовности данных
|
||||||
- `ESP_ERR_INVALID_CRC` - Неверная CRC контрольная сумма
|
- `ESP_ERR_INVALID_CRC` - Неверная CRC контрольная сумма
|
||||||
- `ESP_FAIL` - Ошибка связи I2C
|
|
||||||
|
|
||||||
**Примечание:** Функция выполняет измерение и ожидает ~80 мс готовности данных.
|
**Примечание:** Функция выполняет измерение и ожидает ~80 мс готовности данных.
|
||||||
|
|
||||||
@@ -188,13 +191,12 @@ zh_aht_init(&config, &aht_handle);
|
|||||||
|
|
||||||
**Параметры:**
|
**Параметры:**
|
||||||
|
|
||||||
- `handle` - Указатель на уникальный дескриптор AHT
|
- `handle` - Двойной указатель на уникальный дескриптор AHT (`zh_aht_handle_t **`). Не должен быть NULL.
|
||||||
|
|
||||||
**Возвращает:**
|
**Возвращает:**
|
||||||
|
|
||||||
- `ESP_OK` - Успех
|
- `ESP_OK` - Успех
|
||||||
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
|
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
|
||||||
- `ESP_ERR_NOT_FOUND` - Датчик не инициализирован
|
|
||||||
- `ESP_FAIL` - Ошибка связи I2C
|
- `ESP_FAIL` - Ошибка связи I2C
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -207,25 +209,12 @@ zh_aht_init(&config, &aht_handle);
|
|||||||
|
|
||||||
- Указатель на структуру статистики
|
- Указатель на структуру статистики
|
||||||
|
|
||||||
**Пример:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
const zh_aht_stats_t *stats = zh_aht_get_stats();
|
|
||||||
printf("Ошибки I2C: %ld\n", stats->i2c_driver_error);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### zh_aht_reset_stats()
|
### zh_aht_reset_stats()
|
||||||
|
|
||||||
Сбрасывает счетчик статистики ошибок.
|
Сбрасывает счетчик статистики ошибок.
|
||||||
|
|
||||||
**Пример:**
|
|
||||||
|
|
||||||
```c
|
|
||||||
zh_aht_reset_stats();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Примеры использования
|
## Примеры использования
|
||||||
@@ -237,7 +226,7 @@ zh_aht_reset_stats();
|
|||||||
|
|
||||||
#define I2C_PORT (I2C_NUM_MAX - 1)
|
#define I2C_PORT (I2C_NUM_MAX - 1)
|
||||||
|
|
||||||
zh_aht_handle_t aht_handle = {0};
|
zh_aht_handle_t *aht_handle = NULL;
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
@@ -280,9 +269,9 @@ void app_main(void)
|
|||||||
#define I2C_PORT (I2C_NUM_MAX - 1)
|
#define I2C_PORT (I2C_NUM_MAX - 1)
|
||||||
|
|
||||||
zh_pca9548a_handle_t pca9548a_handle = {0};
|
zh_pca9548a_handle_t pca9548a_handle = {0};
|
||||||
zh_aht_handle_t aht_handle_chan_0 = {0};
|
zh_aht_handle_t *aht_handle_chan_0 = NULL;
|
||||||
zh_aht_handle_t aht_handle_chan_1 = {0};
|
zh_aht_handle_t *aht_handle_chan_1 = NULL;
|
||||||
zh_aht_handle_t aht_handle_chan_2 = {0};
|
zh_aht_handle_t *aht_handle_chan_2 = NULL;
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
@@ -346,10 +335,10 @@ void app_main(void)
|
|||||||
| **Диапазон температуры** | -40 - +85°C |
|
| **Диапазон температуры** | -40 - +85°C |
|
||||||
| **Разрешение измерения влажности** | 0.01% |
|
| **Разрешение измерения влажности** | 0.01% |
|
||||||
| **Разрешение измерения температуры** | 0.01°C |
|
| **Разрешение измерения температуры** | 0.01°C |
|
||||||
| **Адрес I2C** | 0x38, 0x39 |
|
| **Адрес I2C** | 0x38, 0x39, 0x44 |
|
||||||
| **Частота I2C** | До 400 кГц |
|
| **Частота I2C** | До 400 кГц |
|
||||||
| **Время измерения** | ~80 мс |
|
| **Время измерения** | ~80 мс |
|
||||||
| **Поддерживаемые модели** | AHT10, AHT15, AHT20, AHT21, AHT25, AHT30 |
|
| **Поддерживаемые модели** | AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40 |
|
||||||
| **Версия ESP-IDF** | >= 5.0 |
|
| **Версия ESP-IDF** | >= 5.0 |
|
||||||
| **Платформа** | Семейство ESP32 |
|
| **Платформа** | Семейство ESP32 |
|
||||||
| **Язык** | C (C99) |
|
| **Язык** | C (C99) |
|
||||||
@@ -362,8 +351,9 @@ void app_main(void)
|
|||||||
|------------|----------|
|
|------------|----------|
|
||||||
| `ESP_OK` | Операция выполнена успешно |
|
| `ESP_OK` | Операция выполнена успешно |
|
||||||
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или неверная конфигурация) |
|
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или неверная конфигурация) |
|
||||||
| `ESP_ERR_INVALID_STATE` | Датчик не инициализирован |
|
| `ESP_ERR_INVALID_STATE` | Датчик уже инициализирован |
|
||||||
| `ESP_ERR_NOT_FOUND` | Датчик не инициализирован или не отвечает |
|
| `ESP_ERR_NO_MEM` | Ошибка выделения памяти |
|
||||||
|
| `ESP_ERR_NOT_FOUND` | Датчик не отвечает |
|
||||||
| `ESP_ERR_TIMEOUT` | Превышено время ожидания готовности данных |
|
| `ESP_ERR_TIMEOUT` | Превышено время ожидания готовности данных |
|
||||||
| `ESP_ERR_INVALID_CRC` | Неверная CRC контрольная сумма |
|
| `ESP_ERR_INVALID_CRC` | Неверная CRC контрольная сумма |
|
||||||
| `ESP_FAIL` | Общая ошибка (ошибка связи I2C) |
|
| `ESP_FAIL` | Общая ошибка (ошибка связи I2C) |
|
||||||
@@ -412,7 +402,8 @@ void app_main(void)
|
|||||||
- **Время измерения**: Датчик требует ~80 мс для каждого измерения
|
- **Время измерения**: Датчик требует ~80 мс для каждого измерения
|
||||||
- **I2C_ISR_IRAM_SAFE**: Для правильной работы включите `I2C_ISR_IRAM_SAFE` и `I2C_MASTER_ISR_HANDLER_IN_IRAM` в menuconfig
|
- **I2C_ISR_IRAM_SAFE**: Для правильной работы включите `I2C_ISR_IRAM_SAFE` и `I2C_MASTER_ISR_HANDLER_IN_IRAM` в menuconfig
|
||||||
- **Потокобезопасность**: Компонент использует драйвер I2C ESP-IDF, который является потокобезопасным
|
- **Потокобезопасность**: Компонент использует драйвер I2C ESP-IDF, который является потокобезопасным
|
||||||
|
- **Управление памятью**: Все функции API теперь используют двойные указатели для handle, что позволяет автоматически управлять памятью (освобождение при деинициализации, установка в NULL)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Сгенерировано для zh_aht v3.4.0*
|
*Сгенерировано для zh_aht v4.0.0*
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
description: ESP32 ESP-IDF component for AHT10/AHT15/AHT20/AHT21/AHT25/AHT30 humidity & temperature sensor
|
description: ESP32 ESP-IDF component for AHT10/AHT15/AHT20/AHT21/AHT25/AHT30 humidity & temperature sensor
|
||||||
url: https://github.com/aZholtikov/zh_aht
|
url: https://github.com/aZholtikov/zh_aht
|
||||||
version: "3.4.0"
|
version: "4.0.0"
|
||||||
license: "Apache-2.0"
|
license: "Apache-2.0"
|
||||||
maintainers:
|
maintainers:
|
||||||
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
|
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
|
||||||
|
|||||||
+77
-50
@@ -1,5 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* @file zh_aht.h
|
* @file zh_aht.h
|
||||||
|
*
|
||||||
|
* @brief ESP-IDF driver for AHT family sensors (AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40).
|
||||||
|
*
|
||||||
|
* This module provides a high-level interface to control AHT family I2C temperature & humidity sensors.
|
||||||
|
* All devices (AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40) share the same command set, data format, and CRC algorithm.
|
||||||
|
*
|
||||||
|
* @note Supported devices: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40, and compatible clones.
|
||||||
|
* @note Default I2C address: 0x38 (ADR tied to GND). Some variants (e.g., AHT20/30/40 on certain boards) may use 0x39 (ADR tied to VDD).
|
||||||
|
* @note Measurement range and accuracy differ between variants, but communication protocol is identical.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -9,100 +18,118 @@
|
|||||||
#include "driver/i2c_master.h"
|
#include "driver/i2c_master.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AHT sensor initial default values.
|
|
||||||
*/
|
|
||||||
#define ZH_AHT_INIT_CONFIG_DEFAULT() \
|
|
||||||
{ \
|
|
||||||
.i2c_frequency = 400000, \
|
|
||||||
.i2c_address = 0x38}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure for initial initialization of AHT sensor.
|
* @brief Default AHT initialization configuration.
|
||||||
|
*
|
||||||
|
* @note I2C frequency: 400 kHz (fast mode — supported by all AHT variants).
|
||||||
|
* @note I2C address: 0x38 (ADR = GND). If ADR is pulled high (VDD), use 0x39. For AHT40 use 0x44.
|
||||||
|
*
|
||||||
|
* @warning AHT20/30 may be configured to 0x39 by hardware — check your board!
|
||||||
|
*/
|
||||||
|
#define ZH_AHT_INIT_CONFIG_DEFAULT() \
|
||||||
|
{ \
|
||||||
|
.i2c_frequency = 400000, \
|
||||||
|
.i2c_address = 0x38}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Opaque handle type for AHT family sensor instance.
|
||||||
|
*/
|
||||||
|
typedef struct _zh_aht_handle_t zh_aht_handle_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AHT sensor initialization configuration structure.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
i2c_master_bus_handle_t i2c_handle; /*!< Unique I2C bus handle. */
|
i2c_master_bus_handle_t i2c_handle; /*!< I2C bus handle (created via i2c_master_bus_create() or i2c_master_bus_alloc_handle()). */
|
||||||
uint8_t i2c_address; /*!< Sensor I2C address. */
|
uint8_t i2c_address; /*!< I2C address: 0x38 (ADR=GND) or 0x39 (ADR=VDD) or 0x44 (AHT40). */
|
||||||
uint32_t i2c_frequency; /*!< Sensor I2C frequency. */
|
uint32_t i2c_frequency; /*!< I2C clock frequency in Hz (≤ 400000). */
|
||||||
} zh_aht_init_config_t;
|
} zh_aht_init_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief AHT sensor handle.
|
* @brief Error statistics structure.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
bool is_initialized; /*!< Sensor initialization flag. */
|
uint32_t i2c_driver_error; /*!< Number of I2C errors in zh_aht_read()/zh_aht_reset(). */
|
||||||
i2c_master_dev_handle_t dev_handle; /*!< Unique I2C device handle. */
|
|
||||||
} zh_aht_handle_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Structure for error statistics storage.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t i2c_driver_error; /*!< Number of i2c driver error. */
|
|
||||||
} zh_aht_stats_t;
|
} zh_aht_stats_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize AHT sensor.
|
* @brief Initialize an AHT family sensor and allocate handle.
|
||||||
*
|
*
|
||||||
* @param[in] config Pointer to AHT initialized configuration structure. Can point to a temporary variable.
|
* Validates configuration, allocates handle, registers device, probes sensor, and triggers calibration if needed.
|
||||||
* @param[out] handle Pointer to unique AHT handle.
|
|
||||||
*
|
*
|
||||||
* @attention I2C driver must be initialized first.
|
* @param[in] config Pointer to initialized configuration (must be non `NULL`, valid).
|
||||||
|
* @param[out] handle Double pointer to handle structure (`zh_aht_handle_t **`). On success, `*handle` points to newly allocated structure.
|
||||||
*
|
*
|
||||||
* @note Before initialize the sensor recommend initialize zh_aht_init_config_t structure with default values.
|
* @return ESP_OK on success.
|
||||||
*
|
* @return ESP_ERR_INVALID_ARG if `config == NULL` or `handle == NULL`.
|
||||||
* @code zh_aht_init_config_t config = ZH_AHT_INIT_CONFIG_DEFAULT() @endcode
|
* @return ESP_ERR_INVALID_STATE if `*handle != NULL` (already initialized).
|
||||||
*
|
* @return ESP_ERR_NO_MEM if handle allocation failed.
|
||||||
* @return ESP_OK if success or an error code otherwise.
|
* @return ESP_FAIL if I2C registration failed.
|
||||||
|
* @return ESP_ERR_NOT_FOUND if sensor did not respond.
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_aht_init(const zh_aht_init_config_t *config, zh_aht_handle_t *handle);
|
esp_err_t zh_aht_init(const zh_aht_init_config_t *config, zh_aht_handle_t **handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deinitialize AHT sensor.
|
* @brief Deinitialize the AHT sensor and release resources.
|
||||||
*
|
*
|
||||||
* @param[in] handle Pointer to unique AHT handle.
|
* Removes I2C device, frees handle, sets `*handle = NULL`.
|
||||||
*
|
*
|
||||||
* @return ESP_OK if success or an error code otherwise.
|
* @param[in,out] handle Double pointer to handle structure (`zh_aht_handle_t **`). Must not be `NULL`. Set to `NULL` on exit.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success.
|
||||||
|
* @return ESP_ERR_INVALID_ARG if `handle == NULL` or `*handle == NULL` (not initialized).
|
||||||
|
* @return ESP_FAIL if failed to remove I2C device.
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_aht_deinit(zh_aht_handle_t *handle);
|
esp_err_t zh_aht_deinit(zh_aht_handle_t **handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read AHT sensor.
|
* @brief Trigger measurement and read temperature & humidity.
|
||||||
*
|
*
|
||||||
* @param[in] handle Pointer to unique AHT handle.
|
* Sends read command, waits 80 ms, validates CRC/status, and converts to physical units.
|
||||||
* @param[out] humidity Pointer for AHT sensor reading data of humidity.
|
|
||||||
* @param[out] temperature Pointer for AHT sensor reading data of temperature.
|
|
||||||
*
|
*
|
||||||
* @return ESP_OK if success or an error code otherwise.
|
* @param[in] handle Double pointer to handle structure (`zh_aht_handle_t **`). Must not be `NULL`.
|
||||||
|
* @param[out] humidity Pointer to store humidity (%RH).
|
||||||
|
* @param[out] temperature Pointer to store temperature (°C).
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success.
|
||||||
|
* @return ESP_ERR_INVALID_ARG if `handle == NULL` or `*handle == NULL` (not initialized) or `humidity == NULL` or `temperature == NULL`.
|
||||||
|
* @return ESP_FAIL if I2C error.
|
||||||
|
* @return ESP_ERR_TIMEOUT if sensor still busy.
|
||||||
|
* @return ESP_ERR_INVALID_CRC if CRC mismatch.
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_aht_read(zh_aht_handle_t *handle, float *humidity, float *temperature);
|
esp_err_t zh_aht_read(zh_aht_handle_t **handle, float *humidity, float *temperature);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset AHT sensor.
|
* @brief Soft reset the AHT sensor.
|
||||||
*
|
*
|
||||||
* @param[in] handle Pointer to unique AHT handle.
|
* Sends reset command and waits 20 ms for recovery.
|
||||||
*
|
*
|
||||||
* @return ESP_OK if success or an error code otherwise.
|
* @param[in] handle Double pointer to handle structure (`zh_aht_handle_t **`). Must not be `NULL`.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success.
|
||||||
|
* @return ESP_ERR_INVALID_ARG if `handle == NULL` or `*handle == NULL` (not initialized).
|
||||||
|
* @return ESP_FAIL if I2C error.
|
||||||
*/
|
*/
|
||||||
esp_err_t zh_aht_reset(zh_aht_handle_t *handle);
|
esp_err_t zh_aht_reset(zh_aht_handle_t **handle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get error statistics.
|
* @brief Get pointer to internal error statistics.
|
||||||
*
|
*
|
||||||
* @return Pointer to the statistics structure.
|
* @return Pointer to static statistics structure.
|
||||||
*/
|
*/
|
||||||
const zh_aht_stats_t *zh_aht_get_stats(void);
|
const zh_aht_stats_t *zh_aht_get_stats(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reset error statistics.
|
* @brief Reset error statistics counter.
|
||||||
|
*
|
||||||
|
* Sets `i2c_driver_error = 0`.
|
||||||
*/
|
*/
|
||||||
void zh_aht_reset_stats(void);
|
void zh_aht_reset_stats(void);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
3.4.0
|
4.0.0
|
||||||
@@ -13,47 +13,75 @@ static const char *TAG = "zh_aht";
|
|||||||
return err; \
|
return err; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t _aht_reset_command = 0xBA;
|
/**
|
||||||
static const uint8_t _aht_read_command[] = {0xAC, 0x33, 0x00};
|
* @brief Opaque handle structure for the AHT family sensor (AHT10/AHT15/AHT20/AHT21/AHT25/AHT30/AHT40).
|
||||||
static const uint8_t _aht_init_command[] = {0xBE, 0x08, 0x00};
|
*
|
||||||
|
* This structure encapsulates the I2C device handle required to communicate with any sensor
|
||||||
|
* in the AHT family. All AHT sensors share the same I2C protocol, register map, and CRC algorithm.
|
||||||
|
*
|
||||||
|
* @note Supported devices: AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40, and compatible clones.
|
||||||
|
* @note Default I2C addresses:
|
||||||
|
* - AHT10: 0x38 (ADR tied to GND)
|
||||||
|
* - AHT20/30: 0x38 (ADR tied to GND), 0x39 (ADR tied to VDD)
|
||||||
|
* - AHT40: 0x44
|
||||||
|
* @note Some variants may differ in measurement range and accuracy, but not in communication protocol.
|
||||||
|
*
|
||||||
|
* @note Do not instantiate or modify this structure directly. All interactions must go through
|
||||||
|
* the public API functions: zh_aht_init(), zh_aht_read(), zh_aht_deinit(), etc.
|
||||||
|
*/
|
||||||
|
struct _zh_aht_handle_t
|
||||||
|
{
|
||||||
|
i2c_master_dev_handle_t dev_handle; /*!< I2C device handle (ESP-IDF i2c_master API) used for all bus transactions. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AHT family command constants.
|
||||||
|
*
|
||||||
|
* @note All AHT family members (AHT10, AHT15, AHT20, AHT21, AHT25, AHT30, AHT40) support these commands.
|
||||||
|
* @note CRC algorithm, data format, and command structure are identical across family.
|
||||||
|
*/
|
||||||
|
static const uint8_t _aht_reset_command = 0xBA; /*!< Soft reset command (AHT family common). */
|
||||||
|
static const uint8_t _aht_read_command[] = {0xAC, 0x33, 0x00}; /*!< Trigger measurement and read data command. Format: 0xAC (measurement trigger) + 0x33 (normal mode) + 0x00 (unused byte). */
|
||||||
|
static const uint8_t _aht_init_command[] = {0xBE, 0x08, 0x00}; /*!< Self-calibration/initialization command (must be sent if CALIBRATED bit (status[3]) = 0). */
|
||||||
static zh_aht_stats_t _stats = {0};
|
static zh_aht_stats_t _stats = {0};
|
||||||
|
|
||||||
static esp_err_t _zh_aht_validate_config(const zh_aht_init_config_t *config);
|
static esp_err_t _zh_aht_validate_config(const zh_aht_init_config_t *config);
|
||||||
static esp_err_t _zh_aht_i2c_init(const zh_aht_init_config_t *config, zh_aht_handle_t *handle);
|
static esp_err_t _zh_aht_i2c_init(const zh_aht_init_config_t *config, zh_aht_handle_t **handle);
|
||||||
static uint8_t _zh_aht_calc_crc(const uint8_t *buf, size_t len);
|
static uint8_t _zh_aht_calc_crc(const uint8_t *buf, size_t len);
|
||||||
|
|
||||||
esp_err_t zh_aht_init(const zh_aht_init_config_t *config, zh_aht_handle_t *handle)
|
esp_err_t zh_aht_init(const zh_aht_init_config_t *config, zh_aht_handle_t **handle) // -V2008
|
||||||
{
|
{
|
||||||
ZH_LOGI("AHT initialization begin.");
|
ZH_LOGI("AHT initialization begin.");
|
||||||
ZH_ERROR_CHECK(config != NULL && handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT initialization failed. Invalid argument.");
|
ZH_ERROR_CHECK(config != NULL && handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT initialization failed. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(_zh_aht_validate_config(config) == ESP_OK, ESP_FAIL, NULL, "AHT initialization failed. Initial configuration check failed.");
|
ZH_ERROR_CHECK(_zh_aht_validate_config(config) == ESP_OK, ESP_ERR_INVALID_ARG, NULL, "AHT initialization failed. Invalid config.");
|
||||||
ZH_ERROR_CHECK(_zh_aht_i2c_init(config, handle) == ESP_OK, ESP_FAIL, NULL, "AHT initialization failed. Failed to add I2C device.");
|
ZH_ERROR_CHECK(*handle == NULL, ESP_ERR_INVALID_STATE, NULL, "AHT initialization failed. AHT is already initialized.");
|
||||||
handle->is_initialized = true;
|
*handle = heap_caps_calloc(1, sizeof(zh_aht_handle_t), MALLOC_CAP_8BIT);
|
||||||
|
ZH_ERROR_CHECK(*handle != NULL, ESP_ERR_NO_MEM, NULL, "AHT initialization failed. Failed to allocate AHT handle.");
|
||||||
|
ZH_ERROR_CHECK(_zh_aht_i2c_init(config, handle) == ESP_OK, ESP_FAIL, heap_caps_free(*handle); *handle = NULL, "AHT initialization failed. I2C init failed.");
|
||||||
ZH_LOGI("AHT initialization completed successfully.");
|
ZH_LOGI("AHT initialization completed successfully.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t zh_aht_deinit(zh_aht_handle_t *handle)
|
esp_err_t zh_aht_deinit(zh_aht_handle_t **handle)
|
||||||
{
|
{
|
||||||
ZH_LOGI("AHT deinitialization started.");
|
ZH_LOGI("AHT deinitialization started.");
|
||||||
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT deinitialization failed. Invalid argument.");
|
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT deinitialization failed. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "AHT deinitialization failed. AHT not initialized.");
|
ZH_ERROR_CHECK(i2c_master_bus_rm_device((*handle)->dev_handle) == ESP_OK, ESP_FAIL, NULL, "AHT deinitialization failed. I2C remove device failed.");
|
||||||
ZH_ERROR_CHECK(i2c_master_bus_rm_device(handle->dev_handle) == ESP_OK, ESP_FAIL, NULL, "AHT deinitialization failed. I2C remove device failed.");
|
heap_caps_free(*handle);
|
||||||
handle->is_initialized = false;
|
*handle = NULL;
|
||||||
ZH_LOGI("AHT deinitialization completed successfully.");
|
ZH_LOGI("AHT deinitialization completed successfully.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t zh_aht_read(zh_aht_handle_t *handle, float *humidity, float *temperature) // -V2008
|
esp_err_t zh_aht_read(zh_aht_handle_t **handle, float *humidity, float *temperature) // -V2008
|
||||||
{
|
{
|
||||||
ZH_LOGI("AHT read begin.");
|
ZH_LOGI("AHT read begin.");
|
||||||
ZH_ERROR_CHECK(humidity != NULL && temperature != NULL && handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT read fail. Invalid argument.");
|
ZH_ERROR_CHECK(handle != NULL && *handle != NULL && humidity != NULL && temperature != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT read fail. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_NOT_FOUND, NULL, "AHT read fail. AHT not initialized.");
|
|
||||||
uint8_t sensor_data[7] = {0};
|
uint8_t sensor_data[7] = {0};
|
||||||
ZH_ERROR_CHECK(i2c_master_transmit(handle->dev_handle, _aht_read_command, sizeof(_aht_read_command), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(i2c_master_transmit((*handle)->dev_handle, _aht_read_command, sizeof(_aht_read_command), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
||||||
++_stats.i2c_driver_error, "AHT read fail. I2C driver error.");
|
++_stats.i2c_driver_error, "AHT read fail. I2C driver error.");
|
||||||
vTaskDelay(80 / portTICK_PERIOD_MS);
|
vTaskDelay(80 / portTICK_PERIOD_MS);
|
||||||
ZH_ERROR_CHECK(i2c_master_receive(handle->dev_handle, sensor_data, sizeof(sensor_data), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(i2c_master_receive((*handle)->dev_handle, sensor_data, sizeof(sensor_data), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
||||||
++_stats.i2c_driver_error, "AHT read fail. I2C driver error.");
|
++_stats.i2c_driver_error, "AHT read fail. I2C driver error.");
|
||||||
ZH_ERROR_CHECK((sensor_data[0] & 0x80) == 0, ESP_ERR_TIMEOUT, NULL, "AHT read fail. Timeout exceeded.");
|
ZH_ERROR_CHECK((sensor_data[0] & 0x80) == 0, ESP_ERR_TIMEOUT, NULL, "AHT read fail. Timeout exceeded.");
|
||||||
ZH_ERROR_CHECK(_zh_aht_calc_crc(sensor_data, 6) == sensor_data[6], ESP_ERR_INVALID_CRC, NULL, "AHT read fail. Invalid CRC.");
|
ZH_ERROR_CHECK(_zh_aht_calc_crc(sensor_data, 6) == sensor_data[6], ESP_ERR_INVALID_CRC, NULL, "AHT read fail. Invalid CRC.");
|
||||||
@@ -63,12 +91,11 @@ esp_err_t zh_aht_read(zh_aht_handle_t *handle, float *humidity, float *temperatu
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t zh_aht_reset(zh_aht_handle_t *handle)
|
esp_err_t zh_aht_reset(zh_aht_handle_t **handle)
|
||||||
{
|
{
|
||||||
ZH_LOGI("AHT reset begin.");
|
ZH_LOGI("AHT reset begin.");
|
||||||
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT reset fail. Invalid argument.");
|
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "AHT reset fail. Invalid argument.");
|
||||||
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_NOT_FOUND, NULL, "AHT reset fail. AHT not initialized.");
|
ZH_ERROR_CHECK(i2c_master_transmit((*handle)->dev_handle, &_aht_reset_command, sizeof(_aht_reset_command), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(i2c_master_transmit(handle->dev_handle, &_aht_reset_command, sizeof(_aht_reset_command), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
|
||||||
++_stats.i2c_driver_error, "AHT reset fail. I2C driver error.");
|
++_stats.i2c_driver_error, "AHT reset fail. I2C driver error.");
|
||||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||||
ZH_LOGI("AHT reset completed successfully.");
|
ZH_LOGI("AHT reset completed successfully.");
|
||||||
@@ -89,13 +116,13 @@ void zh_aht_reset_stats(void)
|
|||||||
|
|
||||||
static esp_err_t _zh_aht_validate_config(const zh_aht_init_config_t *config)
|
static esp_err_t _zh_aht_validate_config(const zh_aht_init_config_t *config)
|
||||||
{
|
{
|
||||||
ZH_ERROR_CHECK(config->i2c_address == 0x38 || config->i2c_address == 0x39, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C address.");
|
ZH_ERROR_CHECK(config->i2c_address == 0x38 || config->i2c_address == 0x39 || config->i2c_address == 0x44, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C address.");
|
||||||
ZH_ERROR_CHECK(config->i2c_frequency <= 400000, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C frequency.");
|
ZH_ERROR_CHECK(config->i2c_frequency <= 400000, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C frequency.");
|
||||||
ZH_ERROR_CHECK(config->i2c_handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C handle.");
|
ZH_ERROR_CHECK(config->i2c_handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C handle.");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t _zh_aht_i2c_init(const zh_aht_init_config_t *config, zh_aht_handle_t *handle) // -V2008
|
static esp_err_t _zh_aht_i2c_init(const zh_aht_init_config_t *config, zh_aht_handle_t **handle) // -V2008
|
||||||
{
|
{
|
||||||
i2c_device_config_t aht_config = {
|
i2c_device_config_t aht_config = {
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||||
@@ -106,17 +133,17 @@ static esp_err_t _zh_aht_i2c_init(const zh_aht_init_config_t *config, zh_aht_han
|
|||||||
ZH_ERROR_CHECK(i2c_master_bus_add_device(config->i2c_handle, &aht_config, &_dev_handle) == ESP_OK, ESP_FAIL, NULL, "Add I2C device failed.");
|
ZH_ERROR_CHECK(i2c_master_bus_add_device(config->i2c_handle, &aht_config, &_dev_handle) == ESP_OK, ESP_FAIL, NULL, "Add I2C device failed.");
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
ZH_ERROR_CHECK(i2c_master_probe(config->i2c_handle, config->i2c_address, 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_ERR_NOT_FOUND,
|
ZH_ERROR_CHECK(i2c_master_probe(config->i2c_handle, config->i2c_address, 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_ERR_NOT_FOUND,
|
||||||
ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed."), "Sensor not connected or not responded.");
|
{ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "Sensor not connected or not responded.");
|
||||||
uint8_t sensor_data = 0;
|
uint8_t sensor_data = 0;
|
||||||
ZH_ERROR_CHECK(i2c_master_receive(_dev_handle, &sensor_data, sizeof(sensor_data), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(i2c_master_receive(_dev_handle, &sensor_data, sizeof(sensor_data), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed."), "I2C driver error.");
|
{ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "I2C driver error.");
|
||||||
if ((sensor_data & 0x08) == 0)
|
if ((sensor_data & 0x08) == 0)
|
||||||
{
|
{
|
||||||
ZH_ERROR_CHECK(i2c_master_transmit(_dev_handle, _aht_init_command, sizeof(_aht_init_command), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
ZH_ERROR_CHECK(i2c_master_transmit(_dev_handle, _aht_init_command, sizeof(_aht_init_command), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL,
|
||||||
ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed."), "I2C driver error.");
|
{ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "I2C driver error.");
|
||||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
handle->dev_handle = _dev_handle;
|
(*handle)->dev_handle = _dev_handle;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user