examples/generic_switch: Update generic switch wrt spec change

Added momentary_switch, action_switch and momentary_switch_multi_press features and respective features.
Removed fixed and user labels from example because these are removed
from spec.
Removed mfg_binary as it's not needed anymore.
This commit is contained in:
Rohit Jadhav
2024-09-20 16:51:53 +05:30
parent 280f51434f
commit 447e0b1c78
8 changed files with 129 additions and 146 deletions
+54 -15
View File
@@ -2580,9 +2580,7 @@ namespace latching_switch {
uint32_t get_id()
{
// The SwitchFeature enum class is not added in the upstream code.
// Return the code according to the SPEC
return (uint32_t)0x01;
return (uint32_t)Switch::Feature::kLatchingSwitch;
}
esp_err_t add(cluster_t *cluster)
@@ -2590,6 +2588,7 @@ esp_err_t add(cluster_t *cluster)
VerifyOrReturnError((get_feature_map_value(cluster) & feature::momentary_switch::get_id()) != feature::momentary_switch::get_id(), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Latching switch is not supported because momentary switch is present"));
update_feature_map(cluster, get_id());
event::create_switch_latched(cluster);
return ESP_OK;
}
@@ -2599,9 +2598,7 @@ namespace momentary_switch {
uint32_t get_id()
{
// The SwitchFeature enum class is not added in the upstream code.
// Return the code according to the SPEC
return (uint32_t)0x02;
return (uint32_t)Switch::Feature::kMomentarySwitch;
}
esp_err_t add(cluster_t *cluster)
@@ -2609,6 +2606,7 @@ esp_err_t add(cluster_t *cluster)
VerifyOrReturnError((get_feature_map_value(cluster) & feature::latching_switch::get_id()) != feature::latching_switch::get_id(), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch is not supported because latching switch is present"));
update_feature_map(cluster, get_id());
event::create_initial_press(cluster);
return ESP_OK;
}
@@ -2618,16 +2616,19 @@ namespace momentary_switch_release {
uint32_t get_id()
{
// The SwitchFeature enum class is not added in the upstream code.
// Return the code according to the SPEC
return (uint32_t)0x04;
return (uint32_t)Switch::Feature::kMomentarySwitchRelease;
}
esp_err_t add(cluster_t *cluster)
{
VerifyOrReturnError((get_feature_map_value(cluster) & feature::momentary_switch::get_id()) == feature::momentary_switch::get_id(), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch release is not supported because momentary is absent"));
uint32_t as_feature_map = feature::action_switch::get_id();
uint32_t ms_feature_map = feature::momentary_switch::get_id();
uint32_t feature_map = get_feature_map_value(cluster);
VerifyOrReturnError(((feature_map & ms_feature_map) != ms_feature_map) || ((feature_map & as_feature_map) == as_feature_map), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch release is not supported."));
update_feature_map(cluster, get_id());
event::create_short_release(cluster);
return ESP_OK;
}
@@ -2637,17 +2638,23 @@ namespace momentary_switch_long_press {
uint32_t get_id()
{
// The SwitchFeature enum class is not added in the upstream code.
// Return the code according to the SPEC
return (uint32_t)0x08;
return (uint32_t)Switch::Feature::kMomentarySwitchLongPress;
}
esp_err_t add(cluster_t *cluster)
{
uint32_t momentary_and_momentart_switch_release_feature_map = feature::momentary_switch::get_id() | feature::momentary_switch_release::get_id();
VerifyOrReturnError((get_feature_map_value(cluster) & momentary_and_momentart_switch_release_feature_map) == momentary_and_momentart_switch_release_feature_map, ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch long press is not supported because momentary switch and/or momentary switch release is absent"));
uint32_t msr_feature_map = feature::momentary_switch_release::get_id();
uint32_t as_feature_map = feature::action_switch::get_id();
uint32_t ms_feature_map = feature::momentary_switch::get_id();
uint32_t feature_map = get_feature_map_value(cluster);
VerifyOrReturnError((feature_map & ms_feature_map) != ms_feature_map, ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch long press is not supported."));
VerifyOrReturnError(((feature_map & msr_feature_map) != msr_feature_map) && ((feature_map & as_feature_map) != as_feature_map), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch long press is not supported."));
update_feature_map(cluster, get_id());
event::create_long_press(cluster);
event::create_long_release(cluster);
return ESP_OK;
}
@@ -2657,23 +2664,55 @@ namespace momentary_switch_multi_press {
uint32_t get_id()
{
// The SwitchFeature enum class is not added in the upstream code.
// Return the code according to the SPEC
return (uint32_t)0x10;
return (uint32_t)Switch::Feature::kMomentarySwitchMultiPress;
}
esp_err_t add(cluster_t *cluster, config_t *config)
{
uint32_t momentary_and_momentart_switch_release_feature_map = feature::momentary_switch::get_id() | feature::momentary_switch_release::get_id();
VerifyOrReturnError((get_feature_map_value(cluster) & momentary_and_momentart_switch_release_feature_map) == momentary_and_momentart_switch_release_feature_map, ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch multi press is not supported because momentary switch and/or momentary switch releaseis absent"));
uint32_t as_feature_map = feature::action_switch::get_id();
VerifyOrReturnError((get_feature_map_value(cluster) & as_feature_map) != as_feature_map, ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch multi press is not supported because action switch is absent"));
uint32_t ms_feature_map = feature::momentary_switch::get_id();
uint32_t msr_feature_map = feature::momentary_switch_release::get_id();
uint32_t ms_and_msr = ms_feature_map | msr_feature_map;
if ((get_feature_map_value(cluster) & as_feature_map) != as_feature_map) {
if ((get_feature_map_value(cluster) & ms_and_msr) != ms_and_msr) {
ESP_LOGE(TAG, "Momentary switch multi press is not supported.");
return ESP_ERR_NOT_SUPPORTED;
}
event::create_multi_press_ongoing(cluster);
}
update_feature_map(cluster, get_id());
attribute::create_multi_press_max(cluster, config->multi_press_max);
event::create_multi_press_complete(cluster);
return ESP_OK;
}
} /* momentary_switch_multi_press */
namespace action_switch {
uint32_t get_id()
{
return (uint32_t)Switch::Feature::kActionSwitch;
}
esp_err_t add(cluster_t *cluster)
{
if ((get_feature_map_value(cluster) & feature::momentary_switch::get_id()) != feature::momentary_switch::get_id()) {
ESP_LOGE(TAG, "Momentary switch is present");
return ESP_ERR_NOT_SUPPORTED;
}
update_feature_map(cluster, get_id());
return ESP_OK;
}
} /* action_switch */
} /* feature */
} /* switch_cluster */
+8 -1
View File
@@ -1465,7 +1465,14 @@ typedef struct config {
uint32_t get_id();
esp_err_t add(cluster_t *cluster, config_t *config);
} /* momentary_switch_multi_pressy */
} /* momentary_switch_multi_press */
namespace action_switch {
uint32_t get_id();
esp_err_t add(cluster_t *cluster);
} /* action_switch */
} /* feature */
} /* switch_cluster */
+6 -50
View File
@@ -3,16 +3,10 @@
This example creates a Generic Switch device using the ESP
Matter data model.
This example demonstrates the use of few optional data model elements like :
- Fixed Label Cluster : provides a feature for the device to tag an endpoint with zero or more read only labels (demonstrated through nvs).
- User Label Cluster : This cluster provides a feature to tag an endpoint with zero or more labels.
- Taglist Feature of Descriptor Cluster : used to disambiguate sibling endpoints where two or more sibling
endpoints have an overlap in the supported device types with each such endpoint having a unique TagList.
Note:
In order to retrieve the label-list from the fixed-label cluster the two options:
``CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER`` and ``CONFIG_ENABLE_ESP32_DEVICE_INFO_PROVIDER`` have been set through sdkconfig.defaults.
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. Additional Environment Setup
@@ -31,51 +25,13 @@ through menuconfig:
Follow the steps mentioned [here](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/insights.html)
### 1.3 Flash the factory partition
The steps below should be followed in order to access the fixed-labels.
- If monitoring the device using ``idf.py monitor``,press `` Ctrl + ]`` to stop the process.
- The following command must be executed to flash the mfg partition:
```
esptool.py -p [port-name] write_flash 0x10000 mfg_binaries/20202020_3841.bin
```
- Execute the command ``idf.py monitor``
## 2.Commissioning and Control
- Commission the device with ``discriminator: 3841``and `` passcode: 20202020``
- Commission the device with ``discriminator: 3840``and `` passcode: 20202021``
```
chip-tool pairing ble-wifi 0x7283 [ssid] [password] 20202020 3841
chip-tool pairing ble-wifi 0x7283 [ssid] [password] 20202021 3840
```
- Alternatively, below QR Code or Manual pairing code can be used for commissioning
- Manualcode : 34970012334
- QRCode :
- ![QRCode](mfg_binaries/matter_qrcode_20202020_3841.png)
### 2.1 Fixed-Labels
- To read the fixed-labels, use chip-tool.
```
chip-tool fixedlabel read label-list 0x7283 1
```
### 2.2 User-Labels
- The example command given below should be executed to write to the label-list of User Label Cluster.
```
chip-tool userlabel write label-list '[{"label":"room", "value":"bedroom 1"}, {"label":"orientation", "value":"east"}]' 0x7283 1
```
- To read label-list of User Label Cluster execute the command given below.
```
chip-tool userlabel read label-list 0x7283 1
```
### 2.3 Using the TagList Feature
### 2.1 Using the TagList Feature
To read the taglist of the Descriptor cluster execute the command given below.
@@ -83,7 +39,7 @@ To read the taglist of the Descriptor cluster execute the command given below.
chip-tool descriptor read tag-list 0x7283 1
```
## 2. Post Commissioning Setup
## 3. Post Commissioning Setup
This should be followed by: Commission the generic switch device
- Turn on chip-tool interactive mode. ``./chip-tool interactive start``
@@ -91,13 +47,13 @@ This should be followed by: Commission the generic switch device
``switch subscribe-event long-press <min-interval> <max-interval> <destination-id> <endpoint-id>``
- `Double press the boot button` on device so that client will receive event after max-interval.
### 2.1 Latching switch
### 3.1 Latching switch
Following are latching switch events mapped with boot button on device.
- `Double Press` -----------> `switch-latched`
### 2.2 Momentary switch
### 3.2 Momentary switch
Following are momentary switch events mapped with boot button on device.
+57 -47
View File
@@ -36,13 +36,15 @@ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_
}
#if CONFIG_GENERIC_SWITCH_TYPE_LATCHING
static uint8_t latching_switch_previous_position = 0;
static void app_driver_button_switch_latched(void *arg, void *data)
{
ESP_LOGI(TAG, "Switch lached pressed");
gpio_button * button = (gpio_button*)data;
int switch_endpoint_id = (button != NULL) ? get_endpoint(button) : 1;
// Press moves Position from 0 (idle) to 1 (press)
uint8_t newPosition = 1;
// Press moves Position from 0 (idle) to 1 (press) and vice versa
uint8_t newPosition = (latching_switch_previous_position == 1) ? 0 : 1;
latching_switch_previous_position = newPosition;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// SwitchLatched event takes newPosition as event data
@@ -51,18 +53,25 @@ static void app_driver_button_switch_latched(void *arg, void *data)
}
#endif
#if CONFIG_GENERIC_SWITCH_TYPE_MOMENTARY
static int current_number_of_presses_counted = 1;
static bool is_multipress = 0;
static uint8_t idlePosition = 0;
static void app_driver_button_initial_pressed(void *arg, void *data)
{
ESP_LOGI(TAG, "Initial button pressed");
gpio_button * button = (gpio_button*)data;
int switch_endpoint_id = (button != NULL) ? get_endpoint(button) : 1;
// Press moves Position from 0 (idle) to 1 (press)
uint8_t newPosition = 1;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// InitialPress event takes newPosition as event data
switch_cluster::event::send_initial_press(switch_endpoint_id, newPosition);
});
if(!is_multipress) {
ESP_LOGI(TAG, "Initial button pressed");
gpio_button * button = (gpio_button*)data;
int switch_endpoint_id = (button != NULL) ? get_endpoint(button) : 1;
// Press moves Position from 0 (idle) to 1 (press)
uint8_t newPosition = 1;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// InitialPress event takes newPosition as event data
switch_cluster::event::send_initial_press(switch_endpoint_id, newPosition);
});
is_multipress = 1;
}
}
static void app_driver_button_release(void *arg, void *data)
@@ -70,28 +79,9 @@ static void app_driver_button_release(void *arg, void *data)
gpio_button *button = (gpio_button *)data;
int switch_endpoint_id = (button != NULL) ? get_endpoint(button) : 1;
if (iot_button_get_ticks_time((button_handle_t)arg) < 5000) {
ESP_LOGI(TAG, "Short button release");
// Release moves Position from 1 (press) to 0 (idle)
uint8_t previousPosition = 1;
uint8_t newPosition = 0;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, previousPosition, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// ShortRelease event takes previousPosition as event data
switch_cluster::event::send_short_release(switch_endpoint_id, previousPosition);
});
} else {
ESP_LOGI(TAG, "Long button release");
// Release moves Position from 1 (press) to 0 (idle)
uint8_t previousPosition = 1;
uint8_t newPosition = 0;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, previousPosition, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// LongRelease event takes previousPositionPosition as event data
switch_cluster::event::send_long_release(switch_endpoint_id, previousPosition);
});
}
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, idlePosition);
});
}
static void app_driver_button_long_pressed(void *arg, void *data)
@@ -108,8 +98,6 @@ static void app_driver_button_long_pressed(void *arg, void *data)
});
}
static int current_number_of_presses_counted = 1;
static void app_driver_button_multipress_ongoing(void *arg, void *data)
{
ESP_LOGI(TAG, "Multipress Ongoing");
@@ -118,11 +106,25 @@ static void app_driver_button_multipress_ongoing(void *arg, void *data)
// Press moves Position from 0 (idle) to 1 (press)
uint8_t newPosition = 1;
current_number_of_presses_counted++;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// MultiPress Ongoing event takes newPosition and current_number_of_presses_counted as event data
switch_cluster::event::send_multi_press_ongoing(switch_endpoint_id, newPosition, current_number_of_presses_counted);
});
uint16_t endpoint_id = switch_endpoint_id;
uint32_t cluster_id = Switch::Id;
uint32_t attribute_id = Switch::Attributes::FeatureMap::Id;
attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id);
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
attribute::get_val(attribute, &val);
uint32_t feature_map = val.val.u32;
uint32_t msm_feature_map = switch_cluster::feature::momentary_switch_multi_press::get_id();
uint32_t as_feature_map = switch_cluster::feature::action_switch::get_id();
if(((feature_map & msm_feature_map) == msm_feature_map) && ((feature_map & as_feature_map) != as_feature_map)) {
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
// MultiPress Ongoing event takes newPosition and current_number_of_presses_counted as event data
switch_cluster::event::send_multi_press_ongoing(switch_endpoint_id, newPosition, current_number_of_presses_counted);
});
}
}
static void app_driver_button_multipress_complete(void *arg, void *data)
@@ -132,15 +134,24 @@ static void app_driver_button_multipress_complete(void *arg, void *data)
int switch_endpoint_id = (button != NULL) ? get_endpoint(button) : 1;
// Press moves Position from 0 (idle) to 1 (press)
uint8_t previousPosition = 1;
uint8_t newPosition = 0;
static int total_number_of_presses_counted = current_number_of_presses_counted;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, previousPosition, newPosition]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, newPosition);
uint16_t endpoint_id = switch_endpoint_id;
uint32_t cluster_id = Switch::Id;
uint32_t attribute_id = Switch::Attributes::MultiPressMax::Id;
attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id);
esp_matter_attr_val_t val = esp_matter_invalid(NULL);
attribute::get_val(attribute, &val);
uint8_t multipress_max = val.val.u8;
int total_number_of_presses_counted = (current_number_of_presses_counted > multipress_max)? 0:current_number_of_presses_counted;
chip::DeviceLayer::SystemLayer().ScheduleLambda([switch_endpoint_id, previousPosition, total_number_of_presses_counted]() {
chip::app::Clusters::Switch::Attributes::CurrentPosition::Set(switch_endpoint_id, idlePosition);
// MultiPress Complete event takes previousPosition and total_number_of_presses_counted as event data
switch_cluster::event::send_multi_press_complete(switch_endpoint_id, previousPosition, total_number_of_presses_counted);
// Reset current_number_of_presses_counted to initial value
current_number_of_presses_counted = 1;
});
is_multipress = 0;
}
#endif
@@ -162,13 +173,12 @@ app_driver_handle_t app_driver_button_init(gpio_button * button)
#if CONFIG_GENERIC_SWITCH_TYPE_LATCHING
iot_button_register_cb(handle, BUTTON_DOUBLE_CLICK, app_driver_button_switch_latched, button);
iot_button_register_cb(handle, BUTTON_PRESS_DOWN, app_driver_button_switch_latched, button);
#endif
#if CONFIG_GENERIC_SWITCH_TYPE_MOMENTARY
iot_button_register_cb(handle, BUTTON_PRESS_DOWN, app_driver_button_initial_pressed, button);
iot_button_register_cb(handle, BUTTON_PRESS_UP, app_driver_button_release, button);
iot_button_register_cb(handle, BUTTON_LONG_PRESS_START, app_driver_button_long_pressed, button);
iot_button_register_cb(handle, BUTTON_PRESS_REPEAT, app_driver_button_multipress_ongoing, button);
iot_button_register_cb(handle, BUTTON_PRESS_REPEAT_DONE, app_driver_button_multipress_complete, button);
#endif
+4 -24
View File
@@ -170,12 +170,6 @@ static esp_err_t create_button(struct gpio_button* button, node_t* node)
generic_switch_endpoint_id = endpoint::get_id(endpoint);
ESP_LOGI(TAG, "Generic Switch created with endpoint_id %d", generic_switch_endpoint_id);
cluster::fixed_label::config_t fl_config;
cluster_t *fl_cluster = cluster::fixed_label::create(endpoint, &fl_config, CLUSTER_FLAG_SERVER);
cluster::user_label::config_t ul_config;
cluster_t *ul_cluster = cluster::user_label::create(endpoint, &ul_config, CLUSTER_FLAG_SERVER);
/* Add additional features to the node */
cluster_t *cluster = cluster::get(endpoint, Switch::Id);
@@ -185,6 +179,10 @@ static esp_err_t create_button(struct gpio_button* button, node_t* node)
#if CONFIG_GENERIC_SWITCH_TYPE_MOMENTARY
cluster::switch_cluster::feature::momentary_switch::add(cluster);
cluster::switch_cluster::feature::action_switch::add(cluster);
cluster::switch_cluster::feature::momentary_switch_multi_press::config_t msm;
msm.multi_press_max = 5;
cluster::switch_cluster::feature::momentary_switch_multi_press::add(cluster, &msm);
#endif
return err;
@@ -244,24 +242,6 @@ extern "C" void app_main()
SetTagList(1, chip::Span<const Descriptor::Structs::SemanticTagStruct::Type>(gEp1TagList));
SetTagList(2, chip::Span<const Descriptor::Structs::SemanticTagStruct::Type>(gEp2TagList));
nvs_handle_t handle;
nvs_open_from_partition(CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL, "chip-factory", NVS_READWRITE, &handle);
ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to open namespace:chip-factory from partition:"
CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL ", err:%d", err));
int32_t out_value = 0;
if (nvs_get_i32(handle, "fl-sz/1", &out_value) == ESP_ERR_NVS_NOT_FOUND)
{
nvs_set_i32(handle, "fl-sz/1", 2);
nvs_set_str(handle, "fl-k/1/0", "myEP1LBL1");
nvs_set_str(handle, "fl-v/1/0", "valEP1LBL1");
nvs_set_str(handle, "fl-k/1/1", "myEP1LBL2");
nvs_set_str(handle, "fl-v/1/1", "valEP1LBL2");
}
nvs_commit(handle);
nvs_close(handle);
#if CONFIG_ENABLE_CHIP_SHELL
esp_matter::console::diagnostics_register_commands();
esp_matter::console::wifi_register_commands();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

@@ -37,15 +37,6 @@ CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n
# Disable DS Peripheral
CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL=n
# Enable for fixed-label
CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER=y
CONFIG_ENABLE_ESP32_DEVICE_INFO_PROVIDER=y
CONFIG_ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER=y
CONFIG_FACTORY_PARTITION_DAC_PROVIDER=y
CONFIG_FACTORY_DEVICE_INFO_PROVIDER=y
CONFIG_FACTORY_DEVICE_INSTANCE_INFO_PROVIDER=y
CONFIG_FACTORY_COMMISSIONABLE_DATA_PROVIDER=y
# Enable HKDF in mbedtls
CONFIG_MBEDTLS_HKDF_C=y