Working zigbee generic, connected to network and HA

This commit is contained in:
Sam
2025-05-14 12:18:50 +10:00
parent 40691d1884
commit 5d3a5422c4
1585 changed files with 271860 additions and 3 deletions

View File

@@ -0,0 +1,4 @@
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
PRIV_REQUIRES esp_delta_ota app_update
)

View File

@@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee delta OTA Example
*
* 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
#ifdef __cplusplus
extern "C" {
#endif
#define DELTA_OTA_UPGRADE_IMAGE_HEADER_SIZE sizeof(esp_image_header_t)
#define DELTA_OTA_UPGRADE_PATCH_HEADER_SIZE 64
#define DELTA_OTA_UPGRADE_DIGEST_SIZE 32
#define DELTA_OTA_UPGRADE_MAGIC 0xfccdde10
typedef struct esp_delta_ota_ctx_s {
char *header_data;
int header_data_read;
bool verify_patch_flag;
bool chip_id_verified;
} esp_delta_ota_ctx_t;
/**
* @brief Commence a Delta OTA update writing to the specified partition.
* The specified partition is erased to the specified image size.
*
* If image size is not yet known, pass OTA_SIZE_UNKNOWN which will
* cause the entire partition to be erased.
*
* On success, this function allocates memory that remains in use
* until esp_delta_ota_end() is called with the returned handle.
*
* Note: If the rollback option is enabled and the running application has the ESP_OTA_IMG_PENDING_VERIFY state then
* it will lead to the ESP_ERR_OTA_ROLLBACK_INVALID_STATE error. Confirm the running app before to run download a new app,
* use esp_ota_mark_app_valid_cancel_rollback() function for it (this should be done as early as possible when you first download a new application).
*
* @param partition Pointer to info for partition which will receive the OTA update. Required.
* @param image_size Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased.
* @param out_handle On success, returns a handle which should be used for subsequent esp_ota_write() and esp_delta_ota_end() calls.
* @return
* - ESP_OK: OTA operation commenced successfully.
* - ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn't point to an OTA app partition.
* - ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation.
* - ESP_ERR_OTA_PARTITION_CONFLICT: Partition holds the currently running firmware, cannot update in place.
* - ESP_ERR_NOT_FOUND: Partition argument not found in partition table.
* - ESP_ERR_OTA_SELECT_INFO_INVALID: The OTA data partition contains invalid data.
* - ESP_ERR_INVALID_SIZE: Partition doesn't fit in configured flash size.
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
* - ESP_ERR_OTA_ROLLBACK_INVALID_STATE: If the running app has not confirmed state. Before performing an update, the application must be valid.
*/
esp_err_t esp_delta_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle);
/**
* @brief Write Delta OTA update data to partition
*
* This function can be called multiple times as
* data is received during the OTA operation. Data is written
* sequentially to the partition.
*
* @param handle Handle obtained from esp_ota_begin
* @param data Data buffer to write
* @param size Size of data buffer in bytes.
*
* @return
* - ESP_OK: Data was written to flash successfully, or size = 0
* - ESP_ERR_INVALID_ARG: handle is invalid.
* - ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte.
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
* - ESP_ERR_OTA_SELECT_INFO_INVALID: OTA data partition has invalid contents
*/
esp_err_t esp_delta_ota_write(esp_ota_handle_t handle, uint8_t *data, int size);
/**
* @brief Finish Delta OTA update and validate newly written app image.
*
* @param handle Handle obtained from esp_delta_ota_begin().
*
* @note After calling esp_delta_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result).
*
* @return
* - ESP_OK: Newly written OTA app image is valid.
* - ESP_ERR_NOT_FOUND: OTA handle was not found.
* - ESP_ERR_INVALID_ARG: Handle was never written to.
* - ESP_ERR_OTA_VALIDATE_FAILED: OTA image is invalid (either not a valid app image, or - if secure boot is enabled - signature failed to verify.)
* - ESP_ERR_INVALID_STATE: If flash encryption is enabled, this result indicates an internal error writing the final encrypted bytes to flash.
*/
esp_err_t esp_delta_ota_end(esp_ota_handle_t handle);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,209 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee delta OTA Example
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_check.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_app_format.h"
#include "esp_delta_ota.h"
#include "esp_delta_ota_ops.h"
static const char *TAG = "ESP_DELTA_OTA_OPS";
static const esp_partition_t *s_cur_partition = NULL;
static esp_delta_ota_handle_t s_delta_ota_handle = NULL;
static esp_delta_ota_ctx_t *s_delta_ota_ctx = NULL;
static esp_err_t delta_ota_patch_header_verify(void *img_hdr_data)
{
uint8_t sha_256[DELTA_OTA_UPGRADE_DIGEST_SIZE] = { 0 };
uint32_t recv_magic = 0;
uint8_t *digest = NULL;
if (!img_hdr_data) {
return ESP_ERR_INVALID_ARG;
}
recv_magic = *(uint32_t *)img_hdr_data;
if (recv_magic != DELTA_OTA_UPGRADE_MAGIC) {
ESP_LOGE(TAG, "Invalid magic word in patch");
return ESP_ERR_INVALID_ARG;
}
digest = (uint8_t *)(img_hdr_data + sizeof(uint32_t));
esp_partition_get_sha256(s_cur_partition, sha_256);
if (memcmp(sha_256, digest, DELTA_OTA_UPGRADE_DIGEST_SIZE) != 0) {
ESP_LOGE(TAG, "Invalid patch, the SHA256 of the current firmware differs from that in the patch header.");
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
static bool delta_ota_chip_id_verify(void *bin_header_data)
{
esp_image_header_t *header = (esp_image_header_t *)bin_header_data;
ESP_RETURN_ON_FALSE(header->chip_id == CONFIG_IDF_FIRMWARE_CHIP_ID, false, TAG,
"Mismatch chip id, expected %d, found %d", CONFIG_IDF_FIRMWARE_CHIP_ID, header->chip_id);
return true;
}
static esp_err_t delta_ota_write_cb(const uint8_t *buf_p, size_t size, void *user_data)
{
if (size <= 0) {
return ESP_ERR_INVALID_ARG;
}
esp_ota_handle_t ota_handle = (esp_ota_handle_t)user_data;
int index = 0;
if (!s_delta_ota_ctx->chip_id_verified) {
if (s_delta_ota_ctx->header_data_read + size <= DELTA_OTA_UPGRADE_IMAGE_HEADER_SIZE) {
memcpy(s_delta_ota_ctx->header_data + s_delta_ota_ctx->header_data_read, buf_p, size);
s_delta_ota_ctx->header_data_read += size;
return ESP_OK;
} else {
index = DELTA_OTA_UPGRADE_IMAGE_HEADER_SIZE - s_delta_ota_ctx->header_data_read;
memcpy(s_delta_ota_ctx->header_data + s_delta_ota_ctx->header_data_read, buf_p, index);
if (!delta_ota_chip_id_verify(s_delta_ota_ctx->header_data)) {
return ESP_ERR_INVALID_VERSION;
}
s_delta_ota_ctx->chip_id_verified = true;
// Write data in header_data buffer.
esp_err_t err = esp_ota_write(ota_handle, s_delta_ota_ctx->header_data, DELTA_OTA_UPGRADE_IMAGE_HEADER_SIZE);
if (err != ESP_OK) {
return err;
}
}
}
return esp_ota_write(ota_handle, buf_p + index, size - index);
}
static esp_err_t delta_ota_read_cb(uint8_t *buf_p, size_t size, int src_offset)
{
if (size <= 0) {
return ESP_ERR_INVALID_ARG;
}
return esp_partition_read(s_cur_partition, src_offset, buf_p, size);
}
esp_err_t esp_delta_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)
{
esp_err_t ret = ESP_OK;
esp_ota_handle_t ota_handle = 0;
esp_delta_ota_cfg_t cfg = {
.read_cb = &delta_ota_read_cb,
.write_cb_with_user_data = &delta_ota_write_cb,
};
s_cur_partition = esp_ota_get_running_partition();
assert(s_cur_partition);
ESP_RETURN_ON_FALSE(s_cur_partition->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX &&
partition->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX, ESP_ERR_INVALID_ARG, TAG,
"Failed to get partition info of currently or next running app");
ret = esp_ota_begin(partition, image_size, &ota_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to begin OTA partition, status: %s", esp_err_to_name(ret));
cfg.user_data = (void *)ota_handle;
s_delta_ota_handle = esp_delta_ota_init(&cfg);
assert(s_delta_ota_handle);
s_delta_ota_ctx = calloc(1, sizeof(esp_delta_ota_ctx_t));
assert(s_delta_ota_ctx);
s_delta_ota_ctx->header_data = calloc(1, DELTA_OTA_UPGRADE_IMAGE_HEADER_SIZE);
assert(s_delta_ota_ctx->header_data);
*out_handle = ota_handle;
return ret;
}
esp_err_t esp_delta_ota_write(esp_ota_handle_t handle, uint8_t *data, int size)
{
esp_err_t ret = ESP_OK;
static uint8_t *patch_buf = NULL;
static uint8_t patch_len = 0;
const uint8_t *patch_data = (const uint8_t *)data;
int patch_size = size;
if (!s_delta_ota_ctx->verify_patch_flag) {
if (!patch_buf) {
patch_buf = calloc(1, size);
} else {
patch_buf = realloc(patch_buf, patch_len + size);
}
ESP_RETURN_ON_FALSE(patch_buf, ESP_ERR_NO_MEM, TAG, "No memory for delta OTA write");
memcpy(patch_buf + patch_len, data, size);
patch_len += size;
if (patch_len <= DELTA_OTA_UPGRADE_PATCH_HEADER_SIZE) {
return ESP_OK;
}
ret = delta_ota_patch_header_verify(patch_buf);
ESP_GOTO_ON_ERROR(ret, exit, TAG, "Patch Header verification failed, status: %s", esp_err_to_name(ret));
s_delta_ota_ctx->verify_patch_flag = true;
patch_data = (const uint8_t *)patch_buf + DELTA_OTA_UPGRADE_PATCH_HEADER_SIZE;
patch_size = patch_len - DELTA_OTA_UPGRADE_PATCH_HEADER_SIZE;
}
if (s_delta_ota_ctx->verify_patch_flag) {
ret = esp_delta_ota_feed_patch(s_delta_ota_handle, patch_data, patch_size);
ESP_GOTO_ON_ERROR(ret, exit, TAG, "Failed to apply the patch on the source data, status: %s", esp_err_to_name(ret));
}
exit:
if (patch_buf) {
free(patch_buf);
patch_buf = NULL;
patch_len = 0;
}
return ret;
}
esp_err_t esp_delta_ota_end(esp_ota_handle_t handle)
{
esp_err_t ret = ESP_OK;
if (s_delta_ota_ctx) {
if (s_delta_ota_ctx->header_data) {
free(s_delta_ota_ctx->header_data);
s_delta_ota_ctx->header_data = NULL;
}
free(s_delta_ota_ctx);
s_delta_ota_ctx = NULL;
}
ret = esp_delta_ota_finalize(s_delta_ota_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to finish the patch applying operation, status: %s", esp_err_to_name(ret));
ret = esp_delta_ota_deinit(s_delta_ota_handle);
ESP_RETURN_ON_ERROR(ret, TAG, "Failed to clean-up delta ota process, status: %s", esp_err_to_name(ret));
ret = esp_ota_end(handle);
return ret;
}

View File

@@ -0,0 +1,5 @@
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
REQUIRES
led_strip
)

View File

@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee light driver example
*
* 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
#include <stdbool.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
/* light intensity level */
#define LIGHT_DEFAULT_ON 1
#define LIGHT_DEFAULT_OFF 0
/* LED strip configuration */
#define CONFIG_EXAMPLE_STRIP_LED_GPIO 8
#define CONFIG_EXAMPLE_STRIP_LED_NUMBER 1
/** Convert Hue,Saturation,V to RGB
* RGB - [0..0xffff]
* hue - [0..0xff]
* Sat - [0..0xff]
* V always = (ZB_UINT16_MAX-1)
*/
#define HSV_to_RGB(h, s, v, r, g, b ) \
{ \
uint8_t i; \
uint8_t sector = UINT8_MAX/6; \
float f, p, q, t; \
if( s == 0 ) { /* achromatic (grey)*/ \
r = g = b = (v); \
} \
else \
{ \
i = h / sector; /* sector 0 to 5 */ \
f = h % sector; /* factorial part of h*/ \
p = (float)(v * ( 1.0 - (float)s/UINT8_MAX )); \
q = (float)(v * ( 1.0 - (float)s/UINT8_MAX * f/(float)sector )); \
t = (float)(v * ( 1.0 - (float)s/UINT8_MAX * ( 1 - f/(float)sector ) )); \
switch( i ) { \
case 0: r = (v); g = t; b = p; break; \
case 1: r = q; g = (v); b = p; break; \
case 2: r = p; g = (v); b = t; break; \
case 3: r = p; g = q; b = (v); break; \
case 4: r = t; g = p; b = (v); break; \
case 5: \
default: r = (v); g = p; b = q; break; \
} \
} \
}
#define XYZ_to_RGB(X, Y, Z, r, g, b) \
{ \
r = (float)( 3.240479*(X) -1.537150*(Y) -0.498535*(Z)); \
g = (float)(-0.969256*(X) +1.875992*(Y) +0.041556*(Z)); \
b = (float)( 0.055648*(X) -0.204043*(Y) +1.057311*(Z)); \
if(r>1){r=1;} \
if(g>1){g=1;} \
if(b>1){b=1;} \
}
/**
* @brief Set light power (on/off).
*
* @param power The light power to be set
*/
void light_driver_set_power(bool power);
/**
* @brief color light driver init, be invoked where you want to use color light
*
* @param power power on/off
*/
void light_driver_init(bool power);
/**
* @brief Set light level
*
* @param level The light level to be set
*/
void light_driver_set_level(uint8_t level);
/**
* @brief Set light color from RGB
*
* @param red The red color to be set
* @param green The green color to be set
* @param blue The blue color to be set
*/
void light_driver_set_color_RGB(uint8_t red, uint8_t green, uint8_t blue);
/**
* @brief Set light color from color xy
*
* @param color_currentx The color x to be set
* @param color_currenty The color y to be set
*/
void light_driver_set_color_xy(uint16_t color_current_x, uint16_t color_current_y);
/**
* @brief Set light color from hue saturation
*
* @param hue The hue to be set
* @param sat The sat to be set
*/
void light_driver_set_color_hue_sat(uint8_t hue, uint8_t sat);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee light driver example
*
* 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_log.h"
#include "led_strip.h"
#include "light_driver.h"
static led_strip_handle_t s_led_strip;
static uint8_t s_red = 255, s_green = 255, s_blue = 255, s_level = 255;
void light_driver_set_color_xy(uint16_t color_current_x, uint16_t color_current_y)
{
float red_f = 0, green_f = 0, blue_f = 0, color_x, color_y;
color_x = (float)color_current_x / 65535;
color_y = (float)color_current_y / 65535;
/* assume color_Y is full light level value 1 (0-1.0) */
float color_X = color_x / color_y;
float color_Z = (1 - color_x - color_y) / color_y;
/* change from xy to linear RGB NOT sRGB */
XYZ_to_RGB(color_X, 1, color_Z, red_f, green_f, blue_f);
float ratio = (float)s_level / 255;
s_red = (uint8_t)(red_f * (float)255);
s_green = (uint8_t)(green_f * (float)255);
s_blue = (uint8_t)(blue_f * (float)255);
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * ratio, s_green * ratio, s_blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_color_hue_sat(uint8_t hue, uint8_t sat)
{
float red_f, green_f, blue_f;
HSV_to_RGB(hue, sat, UINT8_MAX, red_f, green_f, blue_f);
float ratio = (float)s_level / 255;
s_red = (uint8_t)red_f;
s_green = (uint8_t)green_f;
s_blue = (uint8_t)blue_f;
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * ratio, s_green * ratio, s_blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_color_RGB(uint8_t red, uint8_t green, uint8_t blue)
{
float ratio = (float)s_level / 255;
s_red = red;
s_green = green;
s_blue = blue;
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, red * ratio, green * ratio, blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_power(bool power)
{
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * power, s_green * power, s_blue * power));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_level(uint8_t level)
{
s_level = level;
float ratio = (float)s_level / 255;
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * ratio, s_green * ratio, s_blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_init(bool power)
{
led_strip_config_t led_strip_conf = {
.max_leds = CONFIG_EXAMPLE_STRIP_LED_NUMBER,
.strip_gpio_num = CONFIG_EXAMPLE_STRIP_LED_GPIO,
};
led_strip_rmt_config_t rmt_conf = {
.resolution_hz = 10 * 1000 * 1000, // 10MHz
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&led_strip_conf, &rmt_conf, &s_led_strip));
light_driver_set_power(power);
}

View File

@@ -0,0 +1,5 @@
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
REQUIRES
driver
)

View File

@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee switch driver example
*
* 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
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/* user should configure which I/O port as toggle switch input, default is GPIO9 */
#define GPIO_INPUT_IO_TOGGLE_SWITCH GPIO_NUM_9
/* config button level depends on the pull up/down setting
push button level is on level = 1 when pull-down enable
push button level is on level = 0 when pull-up enable
*/
#define GPIO_INPUT_LEVEL_ON 0
#define ESP_INTR_FLAG_DEFAULT 0
#define PAIR_SIZE(TYPE_STR_PAIR) (sizeof(TYPE_STR_PAIR) / sizeof(TYPE_STR_PAIR[0]))
typedef enum {
SWITCH_IDLE,
SWITCH_PRESS_ARMED,
SWITCH_PRESS_DETECTED,
SWITCH_PRESSED,
SWITCH_RELEASE_DETECTED,
} switch_state_t;
typedef enum {
SWITCH_ON_CONTROL,
SWITCH_OFF_CONTROL,
SWITCH_ONOFF_TOGGLE_CONTROL,
SWITCH_LEVEL_UP_CONTROL,
SWITCH_LEVEL_DOWN_CONTROL,
SWITCH_LEVEL_CYCLE_CONTROL,
SWITCH_COLOR_CONTROL,
} switch_func_t;
typedef struct {
uint32_t pin;
switch_func_t func;
} switch_func_pair_t;
typedef void (*esp_switch_callback_t)(switch_func_pair_t *param);
/**
* @brief init function for switch and callback setup
*
* @param button_func_pair pointer of the button pair.
* @param button_num number of button pair.
* @param cb callback pointer.
*/
bool switch_driver_init(switch_func_pair_t *button_func_pair, uint8_t button_num, esp_switch_callback_t cb);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,159 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee switch driver example
*
* 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_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "switch_driver.h"
/**
* @brief:
* This example code shows how to configure light switch with attribute as well as button switch handler.
*
* @note:
Currently only support toggle switch functionality is available
*
* @note:
* For other possible switch functions (on/off,level up/down,step up/down). User need to implement and create them by themselves
*/
static QueueHandle_t gpio_evt_queue = NULL;
/* button function pair, should be defined in switch example source file */
static switch_func_pair_t *switch_func_pair;
/* call back function pointer */
static esp_switch_callback_t func_ptr;
/* which button is pressed */
static uint8_t switch_num;
static const char *TAG = "ESP_ZB_SWITCH";
static void switch_driver_gpios_intr_enabled(bool enabled);
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
switch_driver_gpios_intr_enabled(false);
xQueueSendFromISR(gpio_evt_queue, (switch_func_pair_t *)arg, NULL);
}
/**
* @brief Enable GPIO (switches refer to) isr
*
* @param enabled enable isr if true.
*/
static void switch_driver_gpios_intr_enabled(bool enabled)
{
for (int i = 0; i < switch_num; ++i) {
if (enabled) {
gpio_intr_enable((switch_func_pair + i)->pin);
} else {
gpio_intr_disable((switch_func_pair + i)->pin);
}
}
}
/**
* @brief Tasks for checking the button event and debounce the switch state
*
* @param arg Unused value.
*/
static void switch_driver_button_detected(void *arg)
{
gpio_num_t io_num = GPIO_NUM_NC;
switch_func_pair_t button_func_pair;
static switch_state_t switch_state = SWITCH_IDLE;
bool evt_flag = false;
for (;;) {
/* check if there is any queue received, if yes read out the button_func_pair */
if (xQueueReceive(gpio_evt_queue, &button_func_pair, portMAX_DELAY)) {
io_num = button_func_pair.pin;
switch_driver_gpios_intr_enabled(false);
evt_flag = true;
}
while (evt_flag) {
bool value = gpio_get_level(io_num);
switch (switch_state) {
case SWITCH_IDLE:
switch_state = (value == GPIO_INPUT_LEVEL_ON) ? SWITCH_PRESS_DETECTED : SWITCH_IDLE;
break;
case SWITCH_PRESS_DETECTED:
switch_state = (value == GPIO_INPUT_LEVEL_ON) ? SWITCH_PRESS_DETECTED : SWITCH_RELEASE_DETECTED;
break;
case SWITCH_RELEASE_DETECTED:
switch_state = SWITCH_IDLE;
/* callback to button_handler */
(*func_ptr)(&button_func_pair);
break;
default:
break;
}
if (switch_state == SWITCH_IDLE) {
switch_driver_gpios_intr_enabled(true);
evt_flag = false;
break;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
}
/**
* @brief init GPIO configuration as well as isr
*
* @param button_func_pair pointer of the button pair.
* @param button_num number of button pair.
*/
static bool switch_driver_gpio_init(switch_func_pair_t *button_func_pair, uint8_t button_num)
{
gpio_config_t io_conf = {};
switch_func_pair = button_func_pair;
switch_num = button_num;
uint64_t pin_bit_mask = 0;
/* set up button func pair pin mask */
for (int i = 0; i < button_num; ++i) {
pin_bit_mask |= (1ULL << (button_func_pair + i)->pin);
}
/* interrupt of falling edge */
io_conf.intr_type = GPIO_INTR_LOW_LEVEL;
io_conf.pin_bit_mask = pin_bit_mask;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 1;
/* configure GPIO with the given settings */
gpio_config(&io_conf);
/* create a queue to handle gpio event from isr */
gpio_evt_queue = xQueueCreate(10, sizeof(switch_func_pair_t));
if ( gpio_evt_queue == 0) {
ESP_LOGE(TAG, "Queue was not created and must not be used");
return false;
}
/* start gpio task */
xTaskCreate(switch_driver_button_detected, "button_detected", 4096, NULL, 10, NULL);
/* install gpio isr service */
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
for (int i = 0; i < button_num; ++i) {
gpio_isr_handler_add((button_func_pair + i)->pin, gpio_isr_handler, (void *) (button_func_pair + i));
}
return true;
}
bool switch_driver_init(switch_func_pair_t *button_func_pair, uint8_t button_num, esp_switch_callback_t cb)
{
if (!switch_driver_gpio_init(button_func_pair, button_num)) {
return false;
}
func_ptr = cb;
return true;
}

View File

@@ -0,0 +1,4 @@
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
REQUIRES driver
)

View File

@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee temperature sensor driver example
*
* 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
#include "driver/temperature_sensor.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Temperature sensor callback
*
* @param[in] temperature temperature value in degrees Celsius from sensor
*
*/
typedef void (*esp_temp_sensor_callback_t)(float temperature);
/**
* @brief init function for temp sensor and callback setup
*
* @param config pointer of temperature sensor config.
* @param update_interval sensor value update interval in seconds.
* @param cb callback pointer.
*
* @return ESP_OK if the driver initialization succeed, otherwise ESP_FAIL.
*/
esp_err_t temp_sensor_driver_init(temperature_sensor_config_t *config, uint16_t update_interval, esp_temp_sensor_callback_t cb);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee temperature sensor driver example
*
* 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 "temp_sensor_driver.h"
#include "esp_err.h"
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
/**
* @brief:
* This example code shows how to configure temperature sensor.
*
* @note:
* The callback will be called with updated temperature sensor value every $interval seconds.
*
*/
/* temperatuer sensor instance handle */
static temperature_sensor_handle_t temp_sensor;
/* call back function pointer */
static esp_temp_sensor_callback_t func_ptr;
/* update interval in seconds */
static uint16_t interval = 1;
static const char *TAG = "ESP_TEMP_SENSOR_DRIVER";
/**
* @brief Tasks for updating the sensor value
*
* @param arg Unused value.
*/
static void temp_sensor_driver_value_update(void *arg)
{
for (;;) {
float tsens_value;
temperature_sensor_get_celsius(temp_sensor, &tsens_value);
if (func_ptr) {
func_ptr(tsens_value);
}
vTaskDelay(pdMS_TO_TICKS(interval * 1000));
}
}
/**
* @brief init temperature sensor
*
* @param config pointer of temperature sensor config.
*/
static esp_err_t temp_sensor_driver_sensor_init(temperature_sensor_config_t *config)
{
ESP_RETURN_ON_ERROR(temperature_sensor_install(config, &temp_sensor),
TAG, "Fail to install on-chip temperature sensor");
ESP_RETURN_ON_ERROR(temperature_sensor_enable(temp_sensor),
TAG, "Fail to enable on-chip temperature sensor");
return (xTaskCreate(temp_sensor_driver_value_update, "sensor_update", 2048, NULL, 10, NULL) == pdTRUE) ? ESP_OK : ESP_FAIL;
}
esp_err_t temp_sensor_driver_init(temperature_sensor_config_t *config, uint16_t update_interval,
esp_temp_sensor_callback_t cb)
{
if (ESP_OK != temp_sensor_driver_sensor_init(config)) {
return ESP_FAIL;
}
func_ptr = cb;
interval = update_interval;
return ESP_OK;
}

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee light driver example
*
* 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
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
#include "esp_check.h"
#include "esp_zigbee_core.h"
/*! Maximum length of ManufacturerName string field */
#define ESP_ZB_ZCL_CLUSTER_ID_BASIC_MANUFACTURER_NAME_MAX_LEN 32
/*! Maximum length of ModelIdentifier string field */
#define ESP_ZB_ZCL_CLUSTER_ID_BASIC_MODEL_IDENTIFIER_MAX_LEN 32
/** optional basic manufacturer information */
typedef struct zcl_basic_manufacturer_info_s {
char *manufacturer_name;
char *model_identifier;
} zcl_basic_manufacturer_info_t;
/**
* @brief Adds manufacturer information to the ZCL basic cluster of endpoint
*
* @param[in] ep_list The pointer to the endpoint list with @p endpoint_id
* @param[in] endpoint_id The endpoint identifier indicating where the ZCL basic cluster resides
* @param[in] info The pointer to the basic manufacturer information
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
*/
esp_err_t esp_zcl_utility_add_ep_basic_manufacturer_info(esp_zb_ep_list_t *ep_list, uint8_t endpoint_id, zcl_basic_manufacturer_info_t *info);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* Zigbee light driver example
*
* 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_check.h"
#include "stdio.h"
#include "string.h"
#include "zcl_utility.h"
#include <stdint.h>
static const char *TAG = "ZCL_UTILITY";
esp_err_t esp_zcl_utility_add_ep_basic_manufacturer_info(esp_zb_ep_list_t *ep_list, uint8_t endpoint_id, zcl_basic_manufacturer_info_t *info)
{
esp_err_t ret = ESP_OK;
esp_zb_cluster_list_t *cluster_list = NULL;
esp_zb_attribute_list_t *basic_cluster = NULL;
cluster_list = esp_zb_ep_list_get_ep(ep_list, endpoint_id);
ESP_RETURN_ON_FALSE(cluster_list, ESP_ERR_INVALID_ARG, TAG, "Failed to find endpoint id: %d in list: %p", endpoint_id, ep_list);
basic_cluster = esp_zb_cluster_list_get_cluster(cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
ESP_RETURN_ON_FALSE(basic_cluster, ESP_ERR_INVALID_ARG, TAG, "Failed to find basic cluster in endpoint: %d", endpoint_id);
ESP_RETURN_ON_FALSE((info && info->manufacturer_name), ESP_ERR_INVALID_ARG, TAG, "Invalid manufacturer name");
ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, info->manufacturer_name));
ESP_RETURN_ON_FALSE((info && info->model_identifier), ESP_ERR_INVALID_ARG, TAG, "Invalid model identifier");
ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, info->model_identifier));
return ret;
}