examples/sensors: Example to demonstrate few sensors

Added the temperature, humidity, and occupancy sensor on different
endpoints.

Fixes https://github.com/espressif/esp-matter/issues/1105
This commit is contained in:
Shubham Patil
2024-10-09 14:56:16 +05:30
parent 2f4ddec095
commit 73b457477d
15 changed files with 786 additions and 0 deletions
+6
View File
@@ -128,3 +128,9 @@ examples/bridge_apps/bridge_cli:
- if: IDF_TARGET in ["esp32", "esp32c3"]
temporary: true
reason: the other targets are not tested yet
examples/sensors:
enable:
- if: IDF_TARGET in ["esp32c3"]
temporary: true
reason: the other targets are not tested yet
+30
View File
@@ -0,0 +1,30 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
if(NOT DEFINED ENV{ESP_MATTER_PATH})
message(FATAL_ERROR "Please set ESP_MATTER_PATH to the path of esp-matter repo")
endif(NOT DEFINED ENV{ESP_MATTER_PATH})
set(PROJECT_VER "1.0")
set(PROJECT_VER_NUMBER 1)
set(ESP_MATTER_PATH $ENV{ESP_MATTER_PATH})
set(MATTER_SDK_PATH ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip)
# This should be done before using the IDF_TARGET variable.
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(EXTRA_COMPONENT_DIRS
"${ESP_MATTER_PATH}/examples/common"
"${MATTER_SDK_PATH}/config/esp32/components"
"${ESP_MATTER_PATH}/components"
${extra_components_dirs_append})
project(sensors)
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H;-Wno-overloaded-virtual" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND)
# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various
# flags that depend on -Wformat
idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND)
+53
View File
@@ -0,0 +1,53 @@
# Matter Sensors
This example demonstrates the integration of temperature and humidity sensors (SHTC3)
and an occupancy sensor (PIR).
This application creates the temperature sensor, humidity sensor, and occupancy sensor
on endpoint 1, 2, and 3 respectively.
See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html)
for more information about building and flashing the firmware.
## Connecting the sensors
- Connecting the SHTC3, temperature and humidity sensor
| ESP32-C3 Pin | SHTC3 Pin |
|--------------|-----------|
| GND | GND |
| 3V3 | VCC |
| GPIO 4 | SDA |
| GPIO 5 | SCL |
- Connecting the PIR sensor
| ESP32-C3 Pin | PIR Pin |
|--------------|---------|
| GND | GND |
| 3V3 | VCC |
| GPIO 7 | Output |
**_NOTE:_**:
- Above mentioned wiring connection is configured by default in the example.
- Ensure that the GPIO pins used for the sensors are correctly configured through menuconfig.
- Modify the configuration parameters as needed for your specific hardware setup.
## Usage
- Commission the app using Matter controller and read the attributes.
Below, we are using chip-tool to commission and subscribe the sensor attributes.
-
```
# Commission
chip-tool pairing ble-wifi 1 (SSID) (PASSPHRASE) 20202021 3840
# Start chip-tool in interactive mode
chip-tool interactive start
# Subscribe to attributes
> temperaturemeasurement subscribe measured-value 3 10 1 1
> relativehumiditymeasurement subscribe measured-value 3 10 1 2
> occupancysensing subscribe occupancy 3 10 1 3
```
+5
View File
@@ -0,0 +1,5 @@
idf_component_register(SRC_DIRS "." "drivers"
PRIV_INCLUDE_DIRS "." "drivers" "${ESP_MATTER_PATH}/examples/common/utils")
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
target_compile_options(${COMPONENT_LIB} PRIVATE "-DCHIP_HAVE_CONFIG_H")
+21
View File
@@ -0,0 +1,21 @@
menu "Example Configuration"
config SHTC3_I2C_SDA_PIN
int "I2C SDA Pin"
default 4
help
GPIO number for I2C master data
config SHTC3_I2C_SCL_PIN
int "I2C SCL Pin"
default 5
help
GPIO number for I2C master clock
config PIR_DATA_PIN
int "PIR Data Pin"
default 7
help
Default PIR Data Pin
endmenu
+226
View File
@@ -0,0 +1,226 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <app/server/CommissioningWindowManager.h>
#include <app/server/Server.h>
#include <bsp/esp-bsp.h>
#include <esp_err.h>
#include <esp_log.h>
#include <esp_matter.h>
#include <esp_matter_ota.h>
#include <nvs_flash.h>
#include <app_openthread_config.h>
#include <app_reset.h>
#include <common_macros.h>
// drivers implemented by this example
#include <drivers/shtc3.h>
#include <drivers/pir.h>
static const char *TAG = "app_main";
using namespace esp_matter;
using namespace esp_matter::attribute;
using namespace esp_matter::endpoint;
using namespace chip::app::Clusters;
// Application cluster specification, 7.18.2.11. Temperature
// represents a temperature on the Celsius scale with a resolution of 0.01°C.
// temp = (temperature in °C) x 100
static void temp_sensor_notification(uint16_t endpoint_id, float temp, void *user_data)
{
// schedule the attribute update so that we can report it from matter thread
chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint_id, temp]() {
attribute_t * attribute = attribute::get(endpoint_id,
TemperatureMeasurement::Id,
TemperatureMeasurement::Attributes::MeasuredValue::Id);
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
attribute::get_val(attribute, &val);
val.val.i16 = static_cast<int16_t>(temp * 100);
attribute::update(endpoint_id, TemperatureMeasurement::Id, TemperatureMeasurement::Attributes::MeasuredValue::Id, &val);
});
}
// Application cluster specification, 2.6.4.1. MeasuredValue Attribute
// represents the humidity in percent.
// humidity = (humidity in %) x 100
static void humidity_sensor_notification(uint16_t endpoint_id, float humidity, void *user_data)
{
// schedule the attribute update so that we can report it from matter thread
chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint_id, humidity]() {
attribute_t * attribute = attribute::get(endpoint_id,
RelativeHumidityMeasurement::Id,
RelativeHumidityMeasurement::Attributes::MeasuredValue::Id);
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
attribute::get_val(attribute, &val);
val.val.u16 = static_cast<uint16_t>(humidity * 100);
attribute::update(endpoint_id, RelativeHumidityMeasurement::Id, RelativeHumidityMeasurement::Attributes::MeasuredValue::Id, &val);
});
}
static void occupancy_sensor_notification(uint16_t endpoint_id, bool occupancy, void *user_data)
{
// schedule the attribute update so that we can report it from matter thread
chip::DeviceLayer::SystemLayer().ScheduleLambda([endpoint_id, occupancy]() {
attribute_t * attribute = attribute::get(endpoint_id,
OccupancySensing::Id,
OccupancySensing::Attributes::Occupancy::Id);
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
attribute::get_val(attribute, &val);
val.val.b = occupancy;
attribute::update(endpoint_id, OccupancySensing::Id, OccupancySensing::Attributes::Occupancy::Id, &val);
});
}
static esp_err_t factory_reset_button_register()
{
button_handle_t push_button;
esp_err_t err = bsp_iot_button_create(&push_button, NULL, BSP_BUTTON_NUM);
VerifyOrReturnError(err == ESP_OK, err);
return app_reset_button_register(push_button);
}
static void open_commissioning_window_if_necessary()
{
VerifyOrReturn(chip::Server::GetInstance().GetFabricTable().FabricCount() == 0);
chip::CommissioningWindowManager & commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager();
VerifyOrReturn(commissionMgr.IsCommissioningWindowOpen() == false);
// After removing last fabric, this example does not remove the Wi-Fi credentials
// and still has IP connectivity so, only advertising on DNS-SD.
CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(chip::System::Clock::Seconds16(300),
chip::CommissioningWindowAdvertisement::kDnssdOnly);
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format());
}
}
static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg)
{
switch (event->Type) {
case chip::DeviceLayer::DeviceEventType::kCommissioningComplete:
ESP_LOGI(TAG, "Commissioning complete");
break;
case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired:
ESP_LOGI(TAG, "Commissioning failed, fail safe timer expired");
break;
case chip::DeviceLayer::DeviceEventType::kFabricRemoved:
ESP_LOGI(TAG, "Fabric removed successfully");
open_commissioning_window_if_necessary();
break;
case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized:
ESP_LOGI(TAG, "BLE deinitialized and memory reclaimed");
break;
default:
break;
}
}
// This callback is invoked when clients interact with the Identify Cluster.
// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light).
static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id,
uint8_t effect_variant, void *priv_data)
{
ESP_LOGI(TAG, "Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant);
return ESP_OK;
}
// This callback is called for every attribute update. The callback implementation shall
// handle the desired attributes and return an appropriate error code. If the attribute
// is not of your interest, please do not return an error code and strictly return ESP_OK.
static esp_err_t app_attribute_update_cb(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id,
uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data)
{
// Since this is just a sensor and we don't expect any writes on our temperature sensor,
// so, return success.
return ESP_OK;
}
extern "C" void app_main()
{
/* Initialize the ESP NVS layer */
nvs_flash_init();
/* Initialize push button on the dev-kit to reset the device */
esp_err_t err = factory_reset_button_register();
ABORT_APP_ON_FAILURE(ESP_OK == err, ESP_LOGE(TAG, "Failed to initialize reset button, err:%d", err));
/* Create a Matter node and add the mandatory Root Node device type on endpoint 0 */
node::config_t node_config;
node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb);
ABORT_APP_ON_FAILURE(node != nullptr, ESP_LOGE(TAG, "Failed to create Matter node"));
// add temperature sensor device
temperature_sensor::config_t temp_sensor_config;
endpoint_t * temp_sensor_ep = temperature_sensor::create(node, &temp_sensor_config, ENDPOINT_FLAG_NONE, NULL);
ABORT_APP_ON_FAILURE(temp_sensor_ep != nullptr, ESP_LOGE(TAG, "Failed to create temperature_sensor endpoint"));
// add the humidity sensor device
humidity_sensor::config_t humidity_sensor_config;
endpoint_t * humidity_sensor_ep = humidity_sensor::create(node, &humidity_sensor_config, ENDPOINT_FLAG_NONE, NULL);
ABORT_APP_ON_FAILURE(humidity_sensor_ep != nullptr, ESP_LOGE(TAG, "Failed to create humidity_sensor endpoint"));
// initialize temperature and humidity sensor driver (shtc3)
static shtc3_sensor_config_t shtc3_config = {
.temperature = {
.cb = temp_sensor_notification,
.endpoint_id = endpoint::get_id(temp_sensor_ep),
},
.humidity = {
.cb = humidity_sensor_notification,
.endpoint_id = endpoint::get_id(humidity_sensor_ep),
},
};
err = shtc3_sensor_init(&shtc3_config);
ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to initialize temperature sensor driver"));
// add the occupancy sensor
occupancy_sensor::config_t occupancy_sensor_config;
occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type =
chip::to_underlying(OccupancySensing::OccupancySensorTypeEnum::kPir);
occupancy_sensor_config.occupancy_sensing.occupancy_sensor_type_bitmap =
chip::to_underlying(OccupancySensing::OccupancySensorTypeBitmap::kPir);
endpoint_t * occupancy_sensor_ep = occupancy_sensor::create(node, &occupancy_sensor_config, ENDPOINT_FLAG_NONE, NULL);
ABORT_APP_ON_FAILURE(occupancy_sensor_ep != nullptr, ESP_LOGE(TAG, "Failed to create occupancy_sensor endpoint"));
// initialize occupancy sensor driver (pir)
static pir_sensor_config_t pir_config = {
.cb = occupancy_sensor_notification,
.endpoint_id = endpoint::get_id(occupancy_sensor_ep),
};
err = pir_sensor_init(&pir_config);
ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to initialize occupancy sensor driver"));
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
/* Set OpenThread platform config */
esp_openthread_platform_config_t config = {
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
};
set_openthread_platform_config(&config);
#endif
/* Matter start */
err = esp_matter::start(app_event_cb);
ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to start Matter, err:%d", err));
}
@@ -0,0 +1,31 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#include <platform/ESP32/OpenthreadLauncher.h>
#include "esp_openthread_types.h"
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
{ \
.radio_mode = RADIO_MODE_NATIVE, \
}
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_NONE, \
}
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \
.storage_partition_name = "nvs", \
.netif_queue_size = 10, \
.task_queue_size = 10, \
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
+64
View File
@@ -0,0 +1,64 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <esp_err.h>
#include <esp_log.h>
#include <driver/gpio.h>
#include <lib/support/CodeUtils.h>
#include <drivers/pir.h>
#define PIR_SENSOR_PIN (static_cast<gpio_num_t>(CONFIG_PIR_DATA_PIN))
typedef struct {
pir_sensor_config_t *config;
bool is_initialized;
} pir_sensor_ctx_t;
static pir_sensor_ctx_t s_ctx;
static void IRAM_ATTR pir_gpio_handler(void *arg)
{
static bool occupancy = false;
bool new_occupancy = gpio_get_level(PIR_SENSOR_PIN);
// we only need to notify application layer if occupancy changed
if (occupancy != new_occupancy) {
occupancy = new_occupancy;
if (s_ctx.config->cb) {
s_ctx.config->cb(s_ctx.config->endpoint_id, new_occupancy, s_ctx.config->user_data);
}
}
}
static void pir_gpio_init(gpio_num_t pin)
{
gpio_reset_pin(pin);
gpio_set_intr_type(pin, GPIO_INTR_ANYEDGE);
gpio_set_direction(pin, GPIO_MODE_INPUT);
gpio_set_pull_mode(pin, GPIO_PULLDOWN_ONLY);
gpio_install_isr_service(0);
gpio_isr_handler_add(pin, pir_gpio_handler, NULL);
}
esp_err_t pir_sensor_init(pir_sensor_config_t *config)
{
if (config == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (s_ctx.is_initialized) {
return ESP_ERR_INVALID_STATE;
}
pir_gpio_init(PIR_SENSOR_PIN);
s_ctx.config = config;
return ESP_OK;
}
+37
View File
@@ -0,0 +1,37 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
// This file implements the PIR sensor driver.
// This is implemented keeping the Matter requirements in mind.
#pragma once
#include <esp_err.h>
using pir_sensor_cb_t = void (*)(uint16_t endpoint_id, bool occupied, void *user_data);
typedef struct {
// This callback functon will be called periodically to report the temperature.
pir_sensor_cb_t cb = NULL;
// endpoint_id associated with temperature sensor
uint16_t endpoint_id;
// user data
void *user_data = NULL;
} pir_sensor_config_t;
/**
* @brief Initialize sensor driver. This function should be called only once
*
* @param config sensor configurations. This should last for the lifetime of the driver
* as driver layer do not make a copy of this object.
*
* @return esp_err_t - ESP_OK on success,
* ESP_ERR_INVALID_ARG if config is NULL
* ESP_ERR_INVALID_STATE if driver is already initialized
* appropriate error code otherwise
*/
esp_err_t pir_sensor_init(pir_sensor_config_t *config);
+179
View File
@@ -0,0 +1,179 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <esp_err.h>
#include <esp_log.h>
#include <esp_timer.h>
#include <esp_random.h>
#include <driver/i2c.h>
#include <lib/support/CodeUtils.h>
#include <drivers/shtc3.h>
static const char * TAG = "shtc3";
#define I2C_MASTER_SCL_IO CONFIG_SHTC3_I2C_SCL_PIN
#define I2C_MASTER_SDA_IO CONFIG_SHTC3_I2C_SDA_PIN
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define SHTC3_SENSOR_ADDR 0x70 /*!< I2C address of SHTC3 sensor */
typedef struct {
shtc3_sensor_config_t *config;
esp_timer_handle_t timer;
bool is_initialized = false;
} shtc3_sensor_ctx_t;
static shtc3_sensor_ctx_t s_ctx;
static esp_err_t shtc3_init_i2c()
{
i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
.clk_speed = I2C_MASTER_FREQ_HZ,
},
};
esp_err_t err = i2c_param_config(I2C_MASTER_NUM, &i2c_conf);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure I2C driver, err:%d", err);
return err;
}
return i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER, 0, 0, 0);
}
static esp_err_t shtc3_read(uint8_t *data, size_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SHTC3_SENSOR_ADDR << 1) | I2C_MASTER_WRITE, true /* enable_ack */);
// Read temperature first then humidity, with clock stretching enabled
i2c_master_write_byte(cmd, 0x7C, true /* enable_ack */);
i2c_master_write_byte(cmd, 0xA2, true /* enable_ack */);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(1000));
i2c_cmd_link_delete(cmd);
cmd = NULL;
// Wait for measurement to complete
vTaskDelay(pdMS_TO_TICKS(15));
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (SHTC3_SENSOR_ADDR << 1) | I2C_MASTER_READ, true /* enable_ack */);
i2c_master_read(cmd, data, size, I2C_MASTER_LAST_NACK);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(1000));
i2c_cmd_link_delete(cmd);
cmd = NULL;
return ESP_OK;
}
// Temperature in degree Celsius
static float shtc3_get_temp(uint16_t raw_temp)
{
return 175.0f * (static_cast<float>(raw_temp) / 65535.0f) - 45.0f;
}
// Humidity in percentage
static float shtc3_get_humidity(uint16_t raw_humidity)
{
return 100.0f * (static_cast<float>(raw_humidity) / 65535.0f);
}
static esp_err_t shtc3_get_read_temp_and_humidity(float & temp, float & humidity)
{
// foreach temperature and humidity: two bytes data, one byte for checksum
uint8_t data[6] = {0};
esp_err_t err = shtc3_read(data, sizeof(data));
if (err != ESP_OK) {
return err;
}
uint16_t raw_temp = (data[0] << 8) | data[1];
uint16_t raw_humidity = (data[3] << 8) | data[4];
temp = shtc3_get_temp(raw_temp);
humidity = shtc3_get_humidity(raw_humidity);
return ESP_OK;
}
static void timer_cb_internal(void *arg)
{
auto *ctx = (shtc3_sensor_ctx_t *) arg;
if (!(ctx && ctx->config)) {
return;
}
float temp, humidity;
esp_err_t err = shtc3_get_read_temp_and_humidity(temp, humidity);
if (err != ESP_OK) {
return;
}
if (ctx->config->temperature.cb) {
ctx->config->temperature.cb(ctx->config->temperature.endpoint_id, temp, ctx->config->user_data);
}
if (ctx->config->humidity.cb) {
ctx->config->humidity.cb(ctx->config->humidity.endpoint_id, humidity, ctx->config->user_data);
}
}
esp_err_t shtc3_sensor_init(shtc3_sensor_config_t *config)
{
if (config == NULL) {
return ESP_ERR_INVALID_ARG;
}
// we need at least one callback so that we can start notifying application layer
if (config->temperature.cb == NULL || config->humidity.cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (s_ctx.is_initialized) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = shtc3_init_i2c();
if (err != ESP_OK) {
return err;
}
// keep the pointer to config
s_ctx.config = config;
esp_timer_create_args_t args = {
.callback = timer_cb_internal,
.arg = &s_ctx,
};
err = esp_timer_create(&args, &s_ctx.timer);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_timer_create failed, err:%d", err);
return err;
}
err = esp_timer_start_periodic(s_ctx.timer, config->interval_ms * 1000);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_timer_start_periodic failed: %d", err);
return err;
}
s_ctx.is_initialized = true;
ESP_LOGI(TAG, "shtc3 initialized successfully");
return ESP_OK;
}
+55
View File
@@ -0,0 +1,55 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
// This file implements the SHTC3 temperature and humidity sensor driver.
// This is implemented keeping the Matter requirements in mind.
//
// Datasheet: https://sensirion.com/media/documents/643F9C8E/63A5A436/Datasheet_SHTC3.pdf
#pragma once
#include <esp_err.h>
using shtc3_sensor_cb_t = void (*)(uint16_t endpoint_id, float value, void *user_data);
typedef struct {
struct {
// This callback functon will be called periodically to report the temperature.
shtc3_sensor_cb_t cb = NULL;
// endpoint_id associated with temperature sensor
uint16_t endpoint_id;
} temperature;
struct {
// This callback functon will be called periodically to report the humidity.
shtc3_sensor_cb_t cb = NULL;
// endpoint_id associated with humidity sensor
uint16_t endpoint_id;
} humidity;
// user data
void *user_data = NULL;
// polling interval in milliseconds, defaults to 5000 ms
uint32_t interval_ms = 5000;
} shtc3_sensor_config_t;
/**
* @brief Initialize sensor driver. This function should be called only once
* When initializing, at least one callback should be provided, else it
* returns ESP_ERR_INVALID_ARG.
*
* @param config sensor configurations. This should last for the lifetime of the driver
* as driver layer do not make a copy of this object.
*
* @return esp_err_t - ESP_OK on success,
* ESP_ERR_INVALID_ARG if config is NULL
* ESP_ERR_INVALID_STATE if driver is already initialized
* appropriate error code otherwise
*/
esp_err_t shtc3_sensor_init(shtc3_sensor_config_t *config);
+8
View File
@@ -0,0 +1,8 @@
dependencies:
espressif/cmake_utilities:
version: 0.*
rules: # will add "optional_component" only when all if clauses are True
- if: "idf_version >=5.0"
- if: "target in [esp32c2]"
esp_bsp_generic:
version: "^1.1.0"
+10
View File
@@ -0,0 +1,10 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted
nvs, data, nvs, 0x10000, 0xC000,
nvs_keys, data, nvs_keys,, 0x1000, encrypted
otadata, data, ota, , 0x2000
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, 0x20000, 0x1E0000,
ota_1, app, ota_1, 0x200000, 0x1E0000,
fctry, data, nvs, 0x3E0000, 0x6000
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table
3 esp_secure_cert, 0x3F, ,0xd000, 0x2000, encrypted
4 nvs, data, nvs, 0x10000, 0xC000,
5 nvs_keys, data, nvs_keys,, 0x1000, encrypted
6 otadata, data, ota, , 0x2000
7 phy_init, data, phy, , 0x1000,
8 ota_0, app, ota_0, 0x20000, 0x1E0000,
9 ota_1, app, ota_1, 0x200000, 0x1E0000,
10 fctry, data, nvs, 0x3E0000, 0x6000
+53
View File
@@ -0,0 +1,53 @@
# Default to 921600 baud when flashing and monitoring device
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
#enable BT
CONFIG_BT_ENABLED=y
CONFIG_BT_NIMBLE_ENABLED=y
#disable BT connection reattempt
CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=n
#enable lwip ipv6 autoconfig
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# Use a custom partition table
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0xC000
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# Button
CONFIG_BUTTON_PERIOD_TIME_MS=20
CONFIG_BUTTON_LONG_PRESS_TIME_MS=5000
# disable softap by default
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
# ESP32-DevKitC Settings
# Buttons
CONFIG_BSP_BUTTONS_NUM=1
CONFIG_BSP_BUTTON_1_TYPE_GPIO=y
CONFIG_BSP_BUTTON_1_GPIO=0
CONFIG_BSP_BUTTON_1_LEVEL=0
# Enable OTA Requestor
CONFIG_ENABLE_OTA_REQUESTOR=y
@@ -0,0 +1,8 @@
CONFIG_IDF_TARGET="esp32c3"
# ESP32-C3-DevKitC-02 Settings
# Buttons
CONFIG_BSP_BUTTONS_NUM=1
CONFIG_BSP_BUTTON_1_TYPE_GPIO=y
CONFIG_BSP_BUTTON_1_GPIO=9
CONFIG_BSP_BUTTON_1_LEVEL=0