Improvements to the multi-plugin example

* adds reset button logic
 * adds support for upt to 16 plugs

Add ability to configure up to 16 plugs

Add factory reset via GPIO

Use bsp instead of device_hal for button initialization

Check if reset button IO pin # conflicts with plugs

Update default IO to be usable accross all supported targets

Updates readme

Adds reset_gpio out arg. Fixed error code usage. Fixed non-static variable names
This commit is contained in:
hankedan000
2024-12-05 08:48:24 -05:00
parent 305d81fb39
commit a41e41b57f
7 changed files with 345 additions and 31 deletions
@@ -19,6 +19,7 @@ include(${ESP_MATTER_PATH}/examples/common/cmake_common/components_include.cmake
set(EXTRA_COMPONENT_DIRS
"${MATTER_SDK_PATH}/config/esp32/components"
"${ESP_MATTER_PATH}/components"
"${ESP_MATTER_PATH}/examples/common"
${extra_components_dirs_append})
project(multiple_on_off_plugin_units)
@@ -11,10 +11,33 @@ To update the existing CONFIG_GPIO_PLUG values, follow these steps:
1. Run the following command to access the configuration menu:
`idf.py menuconfig`
1. Navigate to the "Plugin manager" menu.
1. Update the GPIO pin number values (**Use only available GPIO pins as per the target chip**).
1. Update the GPIO pin number used for the factory reset button and plug output (**Use only available GPIO pins as per the target chip**).
You can update the number of plugin units from same menu.
You can update maximum configurable plugin units from same menu.
The following table defines the default GPIO pin numbers for each supported target device.
| IO Function | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
|----------------------|-------|----------|----------|----------|----------|----------|
| Factory Reset Button | 0 | 9 | 9 | 9 | 9 | 0 |
| Plug 1 | 2 | 2 | 2 | 2 | 2 | 2 |
| Plug 2 | 4 | 4 | 4 | 4 | 4 | 4 |
| Plug 3 | 5 | 5 | 5 | 5 | 5 | 5 |
| Plug 4 | 12 | 6 | 6 | 12 | 12 | 12 |
| Plug 5 | 13 | 7 | 7 | 13 | 13 | 13 |
| Plug 6 | 14 | 8 | 8 | 15 | 14 | 14 |
| Plug 7 | 15 | 10 | 10 | 18 | 22 | 15 |
| Plug 8 | 16 | 18 | 18 | 19 | 25 | 16 |
| Plug 9 | 17 | 0 | 19 | 20 | 26 | 17 |
| Plug 10 | 18 | 1 | 0 | 21 | 27 | 18 |
| Plug 11 | 19 | 3 | 1 | 22 | 0 | 19 |
| Plug 12 | 21 | | 3 | 23 | 1 | 20 |
| Plug 13 | 22 | | | 0 | 3 | 21 |
| Plug 14 | 23 | | | 1 | 8 | 35 |
| Plug 15 | 25 | | | 3 | 10 | 36 |
| Plug 16 | 26 | | | 6 | 11 | 37 |
**Note**: ESP32-C2 and ESP32-C3 do not have enough IO to use all 16 plugs
See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware.
@@ -1,25 +1,174 @@
menu "Plugin manager"
config MAX_CONFIGURABLE_PLUGS
int "Maximum virtual configurable plugs"
default 5
config USER_BUTTON
bool "Use custom GPIO for factory reset button"
default n
config USER_BUTTON_GPIO
int "GPIO pin number for factory reset button"
default 0 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
default 9
depends on USER_BUTTON
config USER_BUTTON_LEVEL
int "GPIO level when factory reset button is active"
default 0
range 0 1
depends on USER_BUTTON
config NUM_VIRTUAL_PLUGS
int "Number of virtual plugs"
default 3
range 1 11 if IDF_TARGET_ESP32C2
range 1 12 if IDF_TARGET_ESP32C3
range 1 16
config GPIO_PLUG_1
int "GPIO pin number for plug 1"
default 3 if IDF_TARGET_ESP32S3
default 2 if !IDF_TARGET_ESP32S3
default 2
depends on (NUM_VIRTUAL_PLUGS >= 1)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_2
int "GPIO pin number for plug 2"
default 4
depends on (NUM_VIRTUAL_PLUGS >= 2)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_3
int "GPIO pin number for plug 3"
default 5
depends on (NUM_VIRTUAL_PLUGS >= 3)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_4
int "GPIO pin number for plug 4"
default 6 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
default 12
depends on (NUM_VIRTUAL_PLUGS >= 4)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_5
int "GPIO pin number for plug 5"
default 7 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
default 13
depends on (NUM_VIRTUAL_PLUGS >= 5)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_6
int "GPIO pin number for plug 6"
default 8 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
default 15 if IDF_TARGET_ESP32C6
default 14
depends on (NUM_VIRTUAL_PLUGS >= 6)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_7
int "GPIO pin number for plug 7"
default 10 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
default 18 if IDF_TARGET_ESP32C6
default 22 if IDF_TARGET_ESP32H2
default 15
depends on (NUM_VIRTUAL_PLUGS >= 7)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_8
int "GPIO pin number for plug 8"
default 18 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
default 19 if IDF_TARGET_ESP32C6
default 25 if IDF_TARGET_ESP32H2
default 16
depends on (NUM_VIRTUAL_PLUGS >= 8)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_9
int "GPIO pin number for plug 9"
default 0 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 20 if IDF_TARGET_ESP32C6
default 26 if IDF_TARGET_ESP32H2
default 17
depends on (NUM_VIRTUAL_PLUGS >= 9)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_10
int "GPIO pin number for plug 10"
default 1 if IDF_TARGET_ESP32C2
default 0 if IDF_TARGET_ESP32C3
default 21 if IDF_TARGET_ESP32C6
default 27 if IDF_TARGET_ESP32H2
default 18
depends on (NUM_VIRTUAL_PLUGS >= 10)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_11
int "GPIO pin number for plug 11"
default 3 if IDF_TARGET_ESP32C2
default 1 if IDF_TARGET_ESP32C3
default 22 if IDF_TARGET_ESP32C6
default 0 if IDF_TARGET_ESP32H2
default 19
depends on (NUM_VIRTUAL_PLUGS >= 11)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_12
int "GPIO pin number for plug 12"
default 3 if IDF_TARGET_ESP32C3
default 23 if IDF_TARGET_ESP32C6
default 1 if IDF_TARGET_ESP32H2
default 20 if IDF_TARGET_ESP32S3
default 21
depends on (NUM_VIRTUAL_PLUGS >= 12)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_13
int "GPIO pin number for plug 13"
default 0 if IDF_TARGET_ESP32C6
default 3 if IDF_TARGET_ESP32H2
default 21 if IDF_TARGET_ESP32S3
default 22
depends on (NUM_VIRTUAL_PLUGS >= 13)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_14
int "GPIO pin number for plug 14"
default 1 if IDF_TARGET_ESP32C6
default 8 if IDF_TARGET_ESP32H2
default 35 if IDF_TARGET_ESP32S3
default 23
depends on (NUM_VIRTUAL_PLUGS >= 14)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_15
int "GPIO pin number for plug 15"
default 3 if IDF_TARGET_ESP32C6
default 10 if IDF_TARGET_ESP32H2
default 36 if IDF_TARGET_ESP32S3
default 25
depends on (NUM_VIRTUAL_PLUGS >= 15)
help
Set GPIO pin value for target chip to create plugin unit
config GPIO_PLUG_16
int "GPIO pin number for plug 16"
default 6 if IDF_TARGET_ESP32C6
default 11 if IDF_TARGET_ESP32H2
default 37 if IDF_TARGET_ESP32S3
default 26
depends on (NUM_VIRTUAL_PLUGS >= 16)
help
Set GPIO pin value for target chip to create plugin unit
endmenu
@@ -6,10 +6,15 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <bsp/esp-bsp.h>
#include <esp_log.h>
#include <iot_button.h>
#include <stdlib.h>
#include <string.h>
#include "bsp/esp_bsp_devkit.h"
#include "driver/gpio.h"
#include "soc/gpio_num.h"
#include "support/CodeUtils.h"
#include <esp_matter.h>
@@ -57,9 +62,9 @@ esp_err_t app_driver_plugin_unit_init(const gpio_plug* plug)
gpio_num_t get_gpio(uint16_t endpoint_id)
{
gpio_num_t gpio_pin = GPIO_NUM_NC;
for (int i = 0; i < s_configure_plugs; i++) {
if (s_plugin_unit_list[i].endpoint_id == endpoint_id) {
gpio_pin = s_plugin_unit_list[i].plug;
for (int i = 0; i < configure_plugs; i++) {
if (plugin_unit_list[i].endpoint_id == endpoint_id) {
gpio_pin = plugin_unit_list[i].plug;
}
}
return gpio_pin;
@@ -85,4 +90,54 @@ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_
return err;
}
app_driver_handle_t app_driver_button_init(gpio_num_t * reset_gpio)
{
VerifyOrReturnValue((reset_gpio), (app_driver_handle_t)NULL, ESP_LOGE(TAG, "reset_gpio cannot be NULL"));
#ifdef CONFIG_USER_BUTTON
*reset_gpio = (gpio_num_t)CONFIG_USER_BUTTON_GPIO;
#elif CONFIG_BSP_BUTTONS_NUM >= 1
*reset_gpio = (gpio_num_t)BSP_BUTTON_1_IO;
#else
*reset_gpio = gpio_num_t::GPIO_NUM_NC;
return (app_driver_handle_t)NULL;
#endif
ESP_LOGI(TAG, "Initializing reset button with gpio pin %d ...", (int)*reset_gpio);
// Make sure button's IO pin isn't assigned to a plug's IO pin
for (int i = 0; i < configure_plugs; i++) {
if (plugin_unit_list[i].plug == *reset_gpio) {
ESP_LOGE(TAG, "Button's gpio pin %d is already configured for plug %d", *reset_gpio, i);
*reset_gpio = gpio_num_t::GPIO_NUM_NC;
return (app_driver_handle_t)NULL;
}
}
/* Initialize button */
app_driver_handle_t reset_handle = NULL;
#ifdef CONFIG_USER_BUTTON
button_config_t config = {
.type = BUTTON_TYPE_GPIO,
.gpio_button_config = {
.gpio_num = CONFIG_USER_BUTTON_GPIO,
.active_level = CONFIG_USER_BUTTON_LEVEL,
}
};
reset_handle = (app_driver_handle_t)iot_button_create(&config);
#else
button_handle_t bsp_buttons[BSP_BUTTON_NUM];
int btn_cnt = 0;// will contain # of buttons that were created by BSP
bsp_iot_button_create(bsp_buttons, &btn_cnt, BSP_BUTTON_NUM);
if (btn_cnt >= 1) {
// return handle to dev board's 1st built-in button
reset_handle = (app_driver_handle_t)bsp_buttons[0];
} else {
ESP_LOGE(TAG, "bsp_iot_button_create() didn't return a usable button count: %d", btn_cnt);
}
#endif
if (!reset_handle) {
*reset_gpio = gpio_num_t::GPIO_NUM_NC;
}
return reset_handle;
}
@@ -14,9 +14,11 @@
#include <esp_matter_console.h>
#include <esp_matter_ota.h>
#include "driver/gpio.h"
#include "soc/gpio_num.h"
#include <common_macros.h>
#include <app_priv.h>
#include <app_reset.h>
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#include <platform/ESP32/OpenthreadLauncher.h>
#endif
@@ -24,6 +26,11 @@
#include <app/server/CommissioningWindowManager.h>
#include <app/server/Server.h>
#define CREATE_PLUG(node, plug_id) \
struct gpio_plug plug##plug_id; \
plug##plug_id.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_##plug_id; \
create_plug(&plug##plug_id, node);
static const char *TAG = "app_main";
using namespace esp_matter;
@@ -32,8 +39,9 @@ using namespace esp_matter::endpoint;
using namespace chip::app::Clusters;
constexpr auto k_timeout_seconds = 300;
uint16_t s_configure_plugs = 0;
plugin_endpoint s_plugin_unit_list[CONFIG_MAX_CONFIGURABLE_PLUGS];
uint16_t configure_plugs = 0;
plugin_endpoint plugin_unit_list[CONFIG_NUM_VIRTUAL_PLUGS];
static gpio_num_t reset_gpio = gpio_num_t::GPIO_NUM_NC;
#if CONFIG_ENABLE_ENCRYPTED_OTA
extern const char decryption_key_start[] asm("_binary_esp_image_encryption_key_pem_start");
@@ -155,11 +163,17 @@ static esp_err_t create_plug(gpio_plug* plug, node_t* node)
return ESP_ERR_INVALID_ARG;
}
// Check if plug's IO pin is already used by reset button
if ((reset_gpio != gpio_num_t::GPIO_NUM_NC) && (reset_gpio == plug->GPIO_PIN_VALUE)) {
ESP_LOGE(TAG, "Reset button already configured for gpio pin : %d", plug->GPIO_PIN_VALUE);
return ESP_ERR_INVALID_STATE;
}
// Check for plug if already configured.
for (int i = 0; i < s_configure_plugs; i++) {
if (s_plugin_unit_list[i].plug == plug->GPIO_PIN_VALUE) {
for (int i = 0; i < configure_plugs; i++) {
if (plugin_unit_list[i].plug == plug->GPIO_PIN_VALUE) {
ESP_LOGE(TAG, "Plug already configured for gpio pin : %d", plug->GPIO_PIN_VALUE);
return ESP_OK;
return ESP_ERR_INVALID_STATE;
}
}
@@ -180,10 +194,10 @@ static esp_err_t create_plug(gpio_plug* plug, node_t* node)
}
// Check for maximum plugs that can be configured.
if (s_configure_plugs < CONFIG_MAX_CONFIGURABLE_PLUGS) {
s_plugin_unit_list[s_configure_plugs].plug = plug->GPIO_PIN_VALUE;
s_plugin_unit_list[s_configure_plugs].endpoint_id = endpoint::get_id(endpoint);
s_configure_plugs++;
if (configure_plugs < CONFIG_NUM_VIRTUAL_PLUGS) {
plugin_unit_list[configure_plugs].plug = plug->GPIO_PIN_VALUE;
plugin_unit_list[configure_plugs].endpoint_id = endpoint::get_id(endpoint);
configure_plugs++;
} else {
ESP_LOGE(TAG, "Maximum plugs configuration limit exceeded!!!");
return ESP_FAIL;
@@ -208,17 +222,75 @@ extern "C" void app_main()
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"));
struct gpio_plug plug1;
plug1.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_1;
create_plug(&plug1, node);
#ifdef CONFIG_GPIO_PLUG_1
CREATE_PLUG(node, 1)
#endif
struct gpio_plug plug2;
plug2.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_2;
create_plug(&plug2, node);
#ifdef CONFIG_GPIO_PLUG_2
CREATE_PLUG(node, 2)
#endif
struct gpio_plug plug3;
plug3.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_3;
create_plug(&plug3, node);
#ifdef CONFIG_GPIO_PLUG_3
CREATE_PLUG(node, 3)
#endif
#ifdef CONFIG_GPIO_PLUG_4
CREATE_PLUG(node, 4)
#endif
#ifdef CONFIG_GPIO_PLUG_5
CREATE_PLUG(node, 5)
#endif
#ifdef CONFIG_GPIO_PLUG_6
CREATE_PLUG(node, 6)
#endif
#ifdef CONFIG_GPIO_PLUG_7
CREATE_PLUG(node, 7)
#endif
#ifdef CONFIG_GPIO_PLUG_8
CREATE_PLUG(node, 8)
#endif
#ifdef CONFIG_GPIO_PLUG_9
CREATE_PLUG(node, 9)
#endif
#ifdef CONFIG_GPIO_PLUG_10
CREATE_PLUG(node, 10)
#endif
#ifdef CONFIG_GPIO_PLUG_11
CREATE_PLUG(node, 11)
#endif
#ifdef CONFIG_GPIO_PLUG_12
CREATE_PLUG(node, 12)
#endif
#ifdef CONFIG_GPIO_PLUG_13
CREATE_PLUG(node, 13)
#endif
#ifdef CONFIG_GPIO_PLUG_14
CREATE_PLUG(node, 14)
#endif
#ifdef CONFIG_GPIO_PLUG_15
CREATE_PLUG(node, 15)
#endif
#ifdef CONFIG_GPIO_PLUG_16
CREATE_PLUG(node, 16)
#endif
// Initialize factory reset button
app_driver_handle_t button_handle = app_driver_button_init(&reset_gpio);
if (button_handle) {
app_reset_button_register(button_handle);
}
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
/* Set OpenThread platform config */
@@ -10,6 +10,7 @@
#include <esp_err.h>
#include <esp_matter.h>
#include "soc/gpio_num.h"
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#include "esp_openthread_types.h"
@@ -28,8 +29,8 @@ struct plugin_endpoint {
gpio_num_t get_gpio(uint16_t endpoint_id);
extern plugin_endpoint s_plugin_unit_list[CONFIG_MAX_CONFIGURABLE_PLUGS];
extern uint16_t s_configure_plugs;
extern plugin_endpoint plugin_unit_list[CONFIG_NUM_VIRTUAL_PLUGS];
extern uint16_t configure_plugs;
typedef void *app_driver_handle_t;
@@ -60,6 +61,17 @@ esp_err_t app_driver_plugin_unit_init(const gpio_plug* plug);
esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id,
uint32_t attribute_id, esp_matter_attr_val_t *val);
/** Initialize the button driver
*
* This initializes the button driver associated with the selected board.
*
* @param[out] reset_gpio GPIO pin # assigned to the reset button
*
* @return Handle on success.
* @return NULL in case of failure.
*/
app_driver_handle_t app_driver_button_init(gpio_num_t * reset_gpio);
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
{ \
@@ -3,4 +3,6 @@ dependencies:
version: 0.*
rules: # will add "optional_component" only when all if clauses are True
- if: "idf_version >=5.0"
- if: "target in [esp32c2]"
- if: "target in [esp32c2]"
esp_bsp_devkit:
version: "1.0.0"