mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 19:13:13 +00:00
Added support of mode select
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
set(SRC_DIRS_LIST "."
|
||||
"${MATTER_SDK_PATH}"
|
||||
"${MATTER_SDK_PATH}/zzz_generated/app-common/app-common/zap-generated/attributes"
|
||||
"${MATTER_SDK_PATH}/src/app"
|
||||
"${MATTER_SDK_PATH}/src/app/server"
|
||||
@@ -61,6 +62,8 @@ set(SRC_DIRS_LIST "."
|
||||
"${MATTER_SDK_PATH}/src/app/clusters/wake-on-lan-server"
|
||||
"${MATTER_SDK_PATH}/src/app/clusters/wifi-network-diagnostics-server"
|
||||
"${MATTER_SDK_PATH}/src/app/clusters/window-covering-server"
|
||||
"${MATTER_SDK_PATH}/src/app/clusters/mode-select-server"
|
||||
"${MATTER_SDK_PATH}/examples/platform/esp32/mode-support"
|
||||
)
|
||||
|
||||
set(INCLUDE_DIRS_LIST "."
|
||||
|
||||
@@ -2176,5 +2176,41 @@ attribute_t *create_control_mode(cluster_t *cluster, uint8_t value)
|
||||
} /* attribute */
|
||||
} /* pump_configuration_and_control */
|
||||
|
||||
namespace mode_select {
|
||||
namespace attribute {
|
||||
|
||||
attribute_t *create_mode_select_description(cluster_t *cluster, char * value, uint16_t length)
|
||||
{
|
||||
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::Description::Id, ATTRIBUTE_FLAG_NONE, esp_matter_char_str(value, length));
|
||||
}
|
||||
|
||||
attribute_t *create_standard_namespace(cluster_t *cluster, const nullable<uint16_t> value)
|
||||
{
|
||||
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::StandardNamespace::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_enum16(value));
|
||||
}
|
||||
|
||||
attribute_t *create_supported_modes(cluster_t *cluster, const uint8_t * value, uint16_t length, uint16_t count)
|
||||
{
|
||||
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::SupportedModes::Id, ATTRIBUTE_FLAG_NONE, esp_matter_array((uint8_t*)value, length, count));
|
||||
}
|
||||
|
||||
attribute_t *create_current_mode(cluster_t *cluster, uint8_t value)
|
||||
{
|
||||
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::CurrentMode::Id, ATTRIBUTE_FLAG_NONE, esp_matter_uint8(value));
|
||||
}
|
||||
|
||||
attribute_t *create_start_up_mode(cluster_t *cluster, nullable<uint8_t> value)
|
||||
{
|
||||
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::StartUpMode::Id, ATTRIBUTE_FLAG_WRITABLE | ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_NONVOLATILE, esp_matter_nullable_uint8(value));
|
||||
}
|
||||
|
||||
attribute_t *create_on_mode(cluster_t *cluster, nullable<uint8_t> value)
|
||||
{
|
||||
return esp_matter::attribute::create(cluster, ModeSelect::Attributes::OnMode::Id, ATTRIBUTE_FLAG_WRITABLE | ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_NONVOLATILE, esp_matter_nullable_uint8(value));
|
||||
}
|
||||
|
||||
} /* attribute */
|
||||
} /* mode_select */
|
||||
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -523,5 +523,16 @@ attribute_t *create_control_mode(cluster_t *cluster, uint8_t value);
|
||||
} /* attribute */
|
||||
} /* pump_configuration_and_control */
|
||||
|
||||
namespace mode_select {
|
||||
namespace attribute {
|
||||
attribute_t *create_mode_select_description(cluster_t *cluster, char * value, uint16_t length);
|
||||
attribute_t *create_standard_namespace(cluster_t *cluster, const nullable<uint16_t> value);
|
||||
attribute_t *create_supported_modes(cluster_t *cluster, const uint8_t * value, uint16_t length, uint16_t count);
|
||||
attribute_t *create_current_mode(cluster_t *cluster, uint8_t value);
|
||||
attribute_t *create_start_up_mode(cluster_t *cluster, nullable<uint8_t> value);
|
||||
attribute_t *create_on_mode(cluster_t *cluster, nullable<uint8_t> value);
|
||||
} /* attribute */
|
||||
} /* mode_select */
|
||||
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -319,6 +319,30 @@ esp_matter_attr_val_t esp_matter_nullable_enum8(nullable<uint8_t> val)
|
||||
return attr_val;
|
||||
}
|
||||
|
||||
esp_matter_attr_val_t esp_matter_enum16(uint16_t val)
|
||||
{
|
||||
esp_matter_attr_val_t attr_val = {
|
||||
.type = ESP_MATTER_VAL_TYPE_ENUM16,
|
||||
.val = {
|
||||
.u16 = val,
|
||||
},
|
||||
};
|
||||
return attr_val;
|
||||
}
|
||||
|
||||
esp_matter_attr_val_t esp_matter_nullable_enum16(nullable<uint16_t> val)
|
||||
{
|
||||
esp_matter_attr_val_t attr_val = {
|
||||
.type = ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16,
|
||||
};
|
||||
if (val.is_null()) {
|
||||
chip::app::NumericAttributeTraits<uint16_t>::SetNull(attr_val.val.u16);
|
||||
} else {
|
||||
attr_val.val.u16 = val.value();
|
||||
}
|
||||
return attr_val;
|
||||
}
|
||||
|
||||
esp_matter_attr_val_t esp_matter_bitmap8(uint8_t val)
|
||||
{
|
||||
esp_matter_attr_val_t attr_val = {
|
||||
@@ -622,6 +646,18 @@ static esp_err_t console_set_handler(int argc, char **argv)
|
||||
uint8_t value = atoi(argv[3]);
|
||||
val = esp_matter_enum8(value);
|
||||
}
|
||||
} else if (type == ESP_MATTER_VAL_TYPE_ENUM16) {
|
||||
if (matter_attribute->IsNullable()) {
|
||||
if (strncmp(argv[3], "null", sizeof("null")) == 0) {
|
||||
val = esp_matter_nullable_enum16(nullable<uint16_t>());
|
||||
} else {
|
||||
uint16_t value = atoi(argv[3]);
|
||||
val = esp_matter_nullable_enum16(value);
|
||||
}
|
||||
} else {
|
||||
uint16_t value = atoi(argv[3]);
|
||||
val = esp_matter_enum16(value);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Type not handled: %d", type);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -834,6 +870,20 @@ static esp_err_t console_get_handler(int argc, char **argv)
|
||||
} else {
|
||||
val = esp_matter_enum8(Traits::StorageToWorking(value));
|
||||
}
|
||||
} else if (type == ESP_MATTER_VAL_TYPE_ENUM16) {
|
||||
using Traits = chip::app::NumericAttributeTraits<uint16_t>;
|
||||
Traits::StorageType value;
|
||||
uint8_t *read_able = Traits::ToAttributeStoreRepresentation(value);
|
||||
get_val_raw(endpoint_id, cluster_id, attribute_id, read_able, sizeof(value));
|
||||
if (matter_attribute->IsNullable()) {
|
||||
if (Traits::IsNullValue(value)) {
|
||||
val = esp_matter_nullable_enum16(nullable<uint16_t>());
|
||||
} else {
|
||||
val = esp_matter_nullable_enum16(Traits::StorageToWorking(value));
|
||||
}
|
||||
} else {
|
||||
val = esp_matter_enum16(Traits::StorageToWorking(value));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Type not handled: %d", type);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -980,6 +1030,10 @@ static esp_matter_val_type_t get_val_type_from_attribute_type(int attribute_type
|
||||
return ESP_MATTER_VAL_TYPE_ENUM8;
|
||||
break;
|
||||
|
||||
case ZCL_ENUM16_ATTRIBUTE_TYPE:
|
||||
return ESP_MATTER_VAL_TYPE_ENUM16;
|
||||
break;
|
||||
|
||||
case ZCL_BITMAP8_ATTRIBUTE_TYPE:
|
||||
return ESP_MATTER_VAL_TYPE_BITMAP8;
|
||||
break;
|
||||
@@ -1011,6 +1065,7 @@ bool val_is_null(esp_matter_attr_val_t *val)
|
||||
return chip::app::NumericAttributeTraits<uint8_t>::IsNullValue(val->val.u8);
|
||||
break;
|
||||
case ESP_MATTER_VAL_TYPE_NULLABLE_UINT16:
|
||||
case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16:
|
||||
case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16:
|
||||
return chip::app::NumericAttributeTraits<uint16_t>::IsNullValue(val->val.u16);
|
||||
break;
|
||||
@@ -1300,6 +1355,24 @@ esp_err_t get_data_from_attr_val(esp_matter_attr_val_t *val, EmberAfAttributeTyp
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_MATTER_VAL_TYPE_ENUM16:
|
||||
case ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16:
|
||||
if (attribute_type) {
|
||||
*attribute_type = ZCL_ENUM16_ATTRIBUTE_TYPE;
|
||||
}
|
||||
if (attribute_size) {
|
||||
*attribute_size = sizeof(uint16_t);
|
||||
}
|
||||
if (value) {
|
||||
using Traits = chip::app::NumericAttributeTraits<uint16_t>;
|
||||
if ((val->type & ESP_MATTER_VAL_NULLABLE_BASE) && Traits::IsNullValue(val->val.u16)) {
|
||||
Traits::SetNull(*(uint16_t *)value);
|
||||
} else {
|
||||
Traits::WorkingToStorage(val->val.u16, *(uint16_t *)value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_MATTER_VAL_TYPE_BITMAP8:
|
||||
case ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8:
|
||||
if (attribute_type) {
|
||||
@@ -1548,6 +1621,22 @@ static esp_err_t get_attr_val_from_data(esp_matter_attr_val_t *val, EmberAfAttri
|
||||
break;
|
||||
}
|
||||
|
||||
case ZCL_ENUM16_ATTRIBUTE_TYPE: {
|
||||
using Traits = chip::app::NumericAttributeTraits<uint16_t>;
|
||||
Traits::StorageType attribute_value;
|
||||
memcpy((uint16_t *)&attribute_value, value, sizeof(Traits::StorageType));
|
||||
if (attribute_metadata->IsNullable()) {
|
||||
if (Traits::IsNullValue(attribute_value)) {
|
||||
*val = esp_matter_nullable_enum16(nullable<uint16_t>());
|
||||
} else {
|
||||
*val = esp_matter_nullable_enum16(attribute_value);
|
||||
}
|
||||
} else {
|
||||
*val = esp_matter_enum16(attribute_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ZCL_BITMAP8_ATTRIBUTE_TYPE: {
|
||||
using Traits = chip::app::NumericAttributeTraits<uint8_t>;
|
||||
Traits::StorageType attribute_value;
|
||||
@@ -1617,8 +1706,7 @@ void val_print(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id,
|
||||
} else if (val->type == ESP_MATTER_VAL_TYPE_INT16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT16) {
|
||||
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIi16 " **********", action,
|
||||
endpoint_id, cluster_id, attribute_id, val->val.i16);
|
||||
} else if (val->type == ESP_MATTER_VAL_TYPE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_BITMAP16
|
||||
|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16) {
|
||||
} else if (val->type == ESP_MATTER_VAL_TYPE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_BITMAP16 || val->type == ESP_MATTER_VAL_TYPE_ENUM16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_UINT16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16 || val->type == ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16) {
|
||||
ESP_LOGI(TAG, "********** %c : Endpoint 0x%04" PRIX16 "'s Cluster 0x%08" PRIX32 "'s Attribute 0x%08" PRIX32 " is %" PRIu16 " **********", action,
|
||||
endpoint_id, cluster_id, attribute_id, val->val.u16);
|
||||
} else if (val->type == ESP_MATTER_VAL_TYPE_INT32|| val->type == ESP_MATTER_VAL_TYPE_NULLABLE_INT32) {
|
||||
|
||||
@@ -72,12 +72,14 @@ typedef enum {
|
||||
ESP_MATTER_VAL_TYPE_UINT64 = 14,
|
||||
/** 8 bit enum */
|
||||
ESP_MATTER_VAL_TYPE_ENUM8 = 15,
|
||||
/** 16 bit enum */
|
||||
ESP_MATTER_VAL_TYPE_ENUM16 = 16,
|
||||
/** 8 bit bitmap */
|
||||
ESP_MATTER_VAL_TYPE_BITMAP8 = 16,
|
||||
ESP_MATTER_VAL_TYPE_BITMAP8 = 17,
|
||||
/** 16 bit bitmap */
|
||||
ESP_MATTER_VAL_TYPE_BITMAP16 = 17,
|
||||
ESP_MATTER_VAL_TYPE_BITMAP16 = 18,
|
||||
/** 32 bit bitmap */
|
||||
ESP_MATTER_VAL_TYPE_BITMAP32 = 18,
|
||||
ESP_MATTER_VAL_TYPE_BITMAP32 = 19,
|
||||
/** nullable types **/
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_INTEGER = ESP_MATTER_VAL_TYPE_INTEGER + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_FLOAT = ESP_MATTER_VAL_TYPE_FLOAT + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
@@ -90,6 +92,7 @@ typedef enum {
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_INT64 = ESP_MATTER_VAL_TYPE_INT64 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_UINT64 = ESP_MATTER_VAL_TYPE_UINT64 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_ENUM8 = ESP_MATTER_VAL_TYPE_ENUM8 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_ENUM16 = ESP_MATTER_VAL_TYPE_ENUM16 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP8 = ESP_MATTER_VAL_TYPE_BITMAP8 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP16 = ESP_MATTER_VAL_TYPE_BITMAP16 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
ESP_MATTER_VAL_TYPE_NULLABLE_BITMAP32= ESP_MATTER_VAL_TYPE_BITMAP32 + ESP_MATTER_VAL_NULLABLE_BASE,
|
||||
@@ -277,6 +280,10 @@ esp_matter_attr_val_t esp_matter_nullable_uint64(nullable<uint64_t> val);
|
||||
esp_matter_attr_val_t esp_matter_enum8(uint8_t val);
|
||||
esp_matter_attr_val_t esp_matter_nullable_enum8(nullable<uint8_t> val);
|
||||
|
||||
/** 16 bit enum */
|
||||
esp_matter_attr_val_t esp_matter_enum16(uint16_t val);
|
||||
esp_matter_attr_val_t esp_matter_nullable_enum16(nullable<uint16_t> val);
|
||||
|
||||
/** 8 bit bitmap */
|
||||
esp_matter_attr_val_t esp_matter_bitmap8(uint8_t val);
|
||||
esp_matter_attr_val_t esp_matter_nullable_bitmap8(nullable<uint8_t> val);
|
||||
|
||||
@@ -1760,6 +1760,54 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags)
|
||||
return cluster;
|
||||
}
|
||||
} /* pump_configuration_and_control */
|
||||
|
||||
namespace mode_select {
|
||||
const function_generic_t function_list[] = {
|
||||
(function_generic_t)emberAfModeSelectClusterServerInitCallback,
|
||||
};
|
||||
const int function_flags = CLUSTER_FLAG_INIT_FUNCTION;
|
||||
|
||||
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_t features)
|
||||
{
|
||||
cluster_t *cluster = cluster::create(endpoint, ModeSelect::Id, flags);
|
||||
if (!cluster) {
|
||||
ESP_LOGE(TAG, "Could not create cluster");
|
||||
return NULL;
|
||||
}
|
||||
if (flags & CLUSTER_FLAG_SERVER) {
|
||||
set_plugin_server_init_callback(cluster, MatterModeSelectPluginServerInitCallback);
|
||||
add_function_list(cluster, function_list, function_flags);
|
||||
}
|
||||
if (flags & CLUSTER_FLAG_CLIENT) {
|
||||
create_default_binding_cluster(endpoint);
|
||||
}
|
||||
|
||||
if (flags & CLUSTER_FLAG_SERVER) {
|
||||
/* Attributes managed internally */
|
||||
global::attribute::create_feature_map(cluster, 0);
|
||||
attribute::create_supported_modes(cluster, NULL, 0, 0);
|
||||
/** Attributes not managed internally **/
|
||||
if (config) {
|
||||
global::attribute::create_cluster_revision(cluster, config->cluster_revision);
|
||||
attribute::create_mode_select_description(cluster, config->mode_select_description, sizeof(config->mode_select_description));
|
||||
attribute::create_standard_namespace(cluster, config->standard_namespace);
|
||||
attribute::create_current_mode(cluster, config->current_mode);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Config is NULL. Cannot add some attributes.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Commands */
|
||||
command::create_change_to_mode(cluster);
|
||||
|
||||
/* Features */
|
||||
if (features & feature::dep_on_off::get_id()) {
|
||||
feature::dep_on_off::add(cluster, &(config->dep_on_off));
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
} /* mode_select */
|
||||
|
||||
#endif /* CONFIG_ESP_MATTER_ENABLE_DATA_MODEL */
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -470,5 +470,18 @@ typedef struct config {
|
||||
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags);
|
||||
} /* pump_configuration_and_control */
|
||||
|
||||
namespace mode_select {
|
||||
typedef struct config {
|
||||
uint16_t cluster_revision;
|
||||
char mode_select_description[64];
|
||||
const nullable<uint16_t> standard_namespace;
|
||||
uint8_t current_mode;
|
||||
feature::dep_on_off::config_t dep_on_off;
|
||||
config() : cluster_revision(1), mode_select_description{0}, standard_namespace(), current_mode(0) {}
|
||||
} config_t;
|
||||
|
||||
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_t features);
|
||||
} /* mode_select */
|
||||
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -986,6 +986,16 @@ static esp_err_t esp_matter_command_callback_go_to_tilt_percentage(const Concret
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_matter_command_callback_change_to_mode(const ConcreteCommandPath &command_path, TLVReader &tlv_data, void *opaque_ptr)
|
||||
{
|
||||
chip::app::Clusters::ModeSelect::Commands::ChangeToMode::DecodableType command_data;
|
||||
CHIP_ERROR error = Decode(tlv_data, command_data);
|
||||
if (error == CHIP_NO_ERROR) {
|
||||
emberAfModeSelectClusterChangeToModeCallback((CommandHandler *)opaque_ptr, command_path, command_data);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_matter_command_callback_instance_action(const ConcreteCommandPath &command_path,
|
||||
TLVReader &tlv_data, void *opaque_ptr)
|
||||
{
|
||||
@@ -2010,6 +2020,17 @@ command_t *create_go_to_tilt_percentage(cluster_t *cluster)
|
||||
} /* command */
|
||||
} /* window_covering */
|
||||
|
||||
namespace mode_select {
|
||||
namespace command {
|
||||
command_t *create_change_to_mode(cluster_t *cluster)
|
||||
{
|
||||
return esp_matter::command::create(cluster, ModeSelect::Commands::ChangeToMode::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_change_to_mode);
|
||||
}
|
||||
|
||||
} /* command */
|
||||
} /* mode_select */
|
||||
|
||||
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
|
||||
@@ -255,5 +255,11 @@ command_t *create_go_to_tilt_percentage(cluster_t *cluster);
|
||||
} /* command */
|
||||
} /* window_covering */
|
||||
|
||||
namespace mode_select {
|
||||
namespace command {
|
||||
command_t *create_change_to_mode(cluster_t *cluster);
|
||||
} /* command */
|
||||
} /* mode_select */
|
||||
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -2068,6 +2068,21 @@ endpoint_t *get_next(endpoint_t *endpoint)
|
||||
return (endpoint_t *)current_endpoint->next;
|
||||
}
|
||||
|
||||
uint16_t get_endpoint_count(node_t *node)
|
||||
{
|
||||
if (!node) {
|
||||
ESP_LOGE(TAG, "Node cannot be NULL");
|
||||
return 0;
|
||||
}
|
||||
uint16_t count = 0;
|
||||
endpoint_t *endpoint = get_first(node);
|
||||
while (endpoint) {
|
||||
count++;
|
||||
endpoint = get_next(endpoint);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint16_t get_id(endpoint_t *endpoint)
|
||||
{
|
||||
if (!endpoint) {
|
||||
|
||||
@@ -201,6 +201,8 @@ endpoint_t *get_first(node_t *node);
|
||||
*/
|
||||
endpoint_t *get_next(endpoint_t *endpoint);
|
||||
|
||||
|
||||
uint16_t get_endpoint_count(node_t *node);
|
||||
/** Get endpoint ID
|
||||
*
|
||||
* Get the endpoint ID for the endpoint.
|
||||
|
||||
@@ -911,6 +911,38 @@ endpoint_t *add(endpoint_t *endpoint, config_t *config)
|
||||
}
|
||||
} /** pump **/
|
||||
|
||||
namespace mode_select_device {
|
||||
uint32_t get_device_type_id()
|
||||
{
|
||||
return ESP_MATTER_MODE_SELECT_DEVICE_TYPE_ID;
|
||||
}
|
||||
|
||||
uint8_t get_device_type_version()
|
||||
{
|
||||
return ESP_MATTER_MODE_SELECT_DEVICE_TYPE_VERSION;
|
||||
}
|
||||
|
||||
endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data)
|
||||
{
|
||||
endpoint_t *endpoint = endpoint::create(node, flags, priv_data);
|
||||
return add(endpoint, config);
|
||||
}
|
||||
|
||||
endpoint_t *add(endpoint_t *endpoint, config_t *config)
|
||||
{
|
||||
if (!endpoint) {
|
||||
ESP_LOGE(TAG, "Could not create endpoint");
|
||||
return NULL;
|
||||
}
|
||||
add_device_type(endpoint, get_device_type_id(), get_device_type_version());
|
||||
|
||||
descriptor::create(endpoint, CLUSTER_FLAG_SERVER);
|
||||
mode_select::create(endpoint, &(config->mode_select), CLUSTER_FLAG_SERVER, ESP_MATTER_NONE_FEATURE_ID);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
} /** mode_select_device **/
|
||||
|
||||
} /* endpoint */
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
#define ESP_MATTER_WINDOW_COVERING_DEVICE_TYPE_VERSION 2
|
||||
#define ESP_MATTER_PUMP_DEVICE_TYPE_ID 0x0303
|
||||
#define ESP_MATTER_PUMP_DEVICE_TYPE_VERSION 2
|
||||
#define ESP_MATTER_MODE_SELECT_DEVICE_TYPE_ID 0x0027
|
||||
#define ESP_MATTER_MODE_SELECT_DEVICE_TYPE_VERSION 1
|
||||
|
||||
namespace esp_matter {
|
||||
|
||||
@@ -417,6 +419,17 @@ endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_dat
|
||||
endpoint_t *add(endpoint_t *endpoint, config_t *config);
|
||||
} /** pump **/
|
||||
|
||||
namespace mode_select_device {
|
||||
typedef struct config {
|
||||
cluster::mode_select::config_t mode_select;
|
||||
} config_t;
|
||||
|
||||
uint32_t get_device_type_id();
|
||||
uint8_t get_device_type_version();
|
||||
endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data);
|
||||
endpoint_t *add(endpoint_t *endpoint, config_t *config);
|
||||
} /** mode_select_device **/
|
||||
|
||||
} /* endpoint */
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -986,5 +986,34 @@ esp_err_t add(cluster_t *cluster, config_t *config)
|
||||
} /* feature */
|
||||
} /* time_format_localization */
|
||||
|
||||
namespace mode_select {
|
||||
namespace feature {
|
||||
|
||||
namespace dep_on_off {
|
||||
|
||||
uint32_t get_id()
|
||||
{
|
||||
// enum class for DepOnOff is not present in the upstream code.
|
||||
// Return the code according to the SPEC
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
esp_err_t add(cluster_t *cluster, config_t *config)
|
||||
{
|
||||
if (!cluster) {
|
||||
ESP_LOGE(TAG, "Cluster cannot be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
update_feature_map(cluster, get_id());
|
||||
|
||||
attribute::create_on_mode(cluster, config->on_mode);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
} /* dep_on_off */
|
||||
|
||||
} /* feature */
|
||||
} /* mode_select */
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -422,5 +422,23 @@ esp_err_t add(cluster_t *cluster, config_t *config);
|
||||
} /* feature */
|
||||
} /* time_format_localization */
|
||||
|
||||
namespace mode_select {
|
||||
namespace feature {
|
||||
|
||||
namespace dep_on_off {
|
||||
|
||||
typedef struct config {
|
||||
nullable<uint8_t> on_mode;
|
||||
config() : on_mode() {}
|
||||
} config_t;
|
||||
|
||||
uint32_t get_id();
|
||||
esp_err_t add(cluster_t *cluster, config_t *config);
|
||||
|
||||
} /* dep_on_off */
|
||||
|
||||
} /* feature */
|
||||
} /* mode_select */
|
||||
|
||||
} /* cluster */
|
||||
} /* esp_matter */
|
||||
|
||||
@@ -1201,3 +1201,50 @@ Please follow the steps below to enable and use encrypted application images for
|
||||
NOTE: There are several ways to store the private key, such as hardcoding it in the firmware, embedding it as a text
|
||||
file, or reading it from the NVS. We have demonstrated the use of the private key by embedding it as a text file in the
|
||||
light example.
|
||||
|
||||
2.7.2 Mode Select
|
||||
==================
|
||||
|
||||
This cluster provides an interface for controlling a characteristic of a device that can be set to one of several predefined values. For example, the light pattern of a disco ball, the mode of a massage chair, or the wash cycle of a laundry machine.
|
||||
|
||||
2.7.2.1 Attribute Supported Modes
|
||||
---------------------------------
|
||||
|
||||
This attribute is the list of supported modes that may be selected for the CurrentMode attribute. Each item in this list represents a unique mode as indicated by the Mode field of the ModeOptionStruct. Each entry in this list SHALL have a unique value for the Mode field.
|
||||
ESP_MATTER uses factory partition to set the values of Supported Modes attribute.
|
||||
|
||||
2.7.2.2 Generate Factory Partition Using mfg_tool
|
||||
-------------------------------------------------
|
||||
|
||||
Use `mfg_tool <https://github.com/espressif/esp-matter/blob/main/tools/mfg_tool/README.md>`__ to generate factory partition of the supported modes attribute.
|
||||
|
||||
2.7.2.2.1 Usage
|
||||
---------------
|
||||
|
||||
::
|
||||
|
||||
cd tools/mfg_tool
|
||||
./mfg_tool.py -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
|
||||
-k path/to/esp-matter/connectedhomeip/connectedhomeip/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
|
||||
-c path/to/esp-matter/connectedhomeip/connectedhomeip/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
|
||||
-cd path/to/esp-matter/connectedhomeip/connectedhomeip/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der \
|
||||
--supported-modes mode1/label1/endpointId/"value\\mfgCode, value\\mfgCode" mode2/label2/endpointId/"value\\mfgCode, value\\mfgCode"
|
||||
|
||||
2.7.2.3 Build example
|
||||
---------------------
|
||||
|
||||
For example we want to use mode_select cluster in light example.
|
||||
|
||||
- In file example/light/app_main.cpp.
|
||||
|
||||
::
|
||||
#include <examples/platform/esp32/mode-support/static-supported-modes-manager.h>
|
||||
{
|
||||
|
||||
cluster::mode_select::config_t ms_config;
|
||||
cluster_t *ms_cluster = cluster::mode_select::create(endpoint, &ms_config, CLUSTER_FLAG_SERVER, ESP_MATTER_NONE_FEATURE_ID);
|
||||
|
||||
ModeSelect::StaticSupportedModesManager obj;
|
||||
obj.InitEndpointArray(get_endpoint_count(node));
|
||||
|
||||
}
|
||||
|
||||
@@ -524,6 +524,9 @@ def get_args():
|
||||
g_dev_inst.add_argument('--fixed-labels', nargs='+',
|
||||
help='List of fixed labels, eg: "0/orientation/up" "1/orientation/down" "2/orientation/down"')
|
||||
|
||||
g_dev_inst.add_argument('--supported-modes', type=str, nargs='+', required=False,
|
||||
help='List of supported modes, eg: mode1/label1/ep/"tagValue1\\mfgCode, tagValue2\\mfgCode" mode2/label2/ep/"tagValue1\\mfgCode, tagValue2\\mfgCode" mode3/label3/ep/"tagValue1\\mfgCode, tagValue2\\mfgCode"')
|
||||
|
||||
g_basic = parser.add_argument_group('Few more Basic clusters options')
|
||||
g_basic.add_argument('--product-label', help='Product label')
|
||||
g_basic.add_argument('--product-url', help='Product URL')
|
||||
@@ -598,6 +601,42 @@ def add_optional_KVs(args):
|
||||
chip_factory_append('fl-k/{:x}/{:x}'.format(int(key), i), 'data', 'string', list(entry.keys())[0])
|
||||
chip_factory_append('fl-v/{:x}/{:x}'.format(int(key), i), 'data', 'string', list(entry.values())[0])
|
||||
|
||||
# SupportedModes are stored as multiple entries
|
||||
# - sm-sz/<ep> : number of supported modes for the endpoint
|
||||
# - sm-label/<ep>/<index> : supported modes label key for the endpoint and index
|
||||
# - sm-mode/<ep>/<index> : supported modes mode key for the endpoint and index
|
||||
# - sm-st-sz/<ep>/<index> : supported modes SemanticTag key for the endpoint and index
|
||||
# - st-v/<ep>/<index>/<ind> : semantic tag value key for the endpoint and index and ind
|
||||
# - st-mfg/<ep>/<index>/<ind> : semantic tag mfg code key for the endpoint and index and ind
|
||||
if (args.supported_modes is not None):
|
||||
dictionary = get_supported_modes_dict(args.supported_modes)
|
||||
for ep in dictionary.keys():
|
||||
chip_factory_append('sm-sz/{:x}'.format(int(ep)), 'data', 'u32', len(dictionary[ep]))
|
||||
|
||||
for i in range(len(dictionary[ep])):
|
||||
item = dictionary[ep][i]
|
||||
|
||||
chip_factory_append('sm-label/{:x}/{:x}'.format(int(ep), i), 'data', 'string', item["Label"])
|
||||
chip_factory_append('sm-mode/{:x}/{:x}'.format(int(ep), i), 'data', 'u32', item["Mode"])
|
||||
chip_factory_append('sm-st-sz/{:x}/{:x}'.format(int(ep), i), 'data', 'u32', len(item["Semantic_Tag"]))
|
||||
|
||||
for j in range(len(item["Semantic_Tag"])):
|
||||
entry = item["Semantic_Tag"][j]
|
||||
|
||||
_value = {
|
||||
'type': 'data',
|
||||
'encoding': 'u32',
|
||||
'value': entry["value"]
|
||||
}
|
||||
_mfg_code = {
|
||||
'type': 'data',
|
||||
'encoding': 'u32',
|
||||
'value': entry["mfgCode"]
|
||||
}
|
||||
|
||||
chip_factory_append('st-v/{:x}/{:x}/{:x}'.format(int(ep), i, j), 'data', 'u32', entry["value"])
|
||||
chip_factory_append('st-mfg/{:x}/{:x}/{:x}'.format(int(ep), i, j), 'data', 'u32', entry["mfgCode"])
|
||||
|
||||
# Keys from basic clusters
|
||||
if args.product_label is not None:
|
||||
chip_factory_append('product-label', 'data', 'string', args.product_label)
|
||||
|
||||
@@ -234,6 +234,33 @@ def get_fixed_label_dict(fixed_labels):
|
||||
return fl_dict
|
||||
|
||||
|
||||
# get_supported_modes_dict() converts the list of strings to per endpoint dictionaries.
|
||||
# example input : ['0/label1/1/"1\0x8000, 2\0x8000", 1/label2/1/"1\0x8000, 2\0x8000"']
|
||||
# example outout : {'1': [{'Label': 'label1', 'Mode': 0, 'Semantic_Tag': [{'value': 1, 'mfgCode': 32768}, {'value': 2, 'mfgCode': 32768}]}, {'Label': 'label2', 'Mode': 1, 'Semantic_Tag': [{'value': 1, 'mfgCode': 32768}, {'value': 2, 'mfgCode': 32768}]}]}
|
||||
|
||||
|
||||
def get_supported_modes_dict(supported_modes):
|
||||
output_dict = {}
|
||||
|
||||
for mode_str in supported_modes:
|
||||
mode_label_strs = mode_str.split('/')
|
||||
mode = mode_label_strs[0]
|
||||
label = mode_label_strs[1]
|
||||
ep = mode_label_strs[2]
|
||||
|
||||
semantic_tag_strs = mode_label_strs[3].split(', ')
|
||||
semantic_tags = [{"value": int(v.split('\\')[0]), "mfgCode": int(v.split('\\')[1], 16)} for v in semantic_tag_strs]
|
||||
|
||||
mode_dict = {"Label": label, "Mode": int(mode), "Semantic_Tag": semantic_tags}
|
||||
|
||||
if ep in output_dict:
|
||||
output_dict[ep].append(mode_dict)
|
||||
else:
|
||||
output_dict[ep] = [mode_dict]
|
||||
|
||||
return output_dict
|
||||
|
||||
|
||||
# Convert the certificate in PEM format to DER format
|
||||
def convert_x509_cert_from_pem_to_der(pem_file, out_der_file):
|
||||
with open(pem_file, 'rb') as f:
|
||||
|
||||
Reference in New Issue
Block a user