From cf0d7c16be1a6557ecc1c6f720795fdb318ded3d Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Wed, 12 Jul 2023 17:55:28 +0530 Subject: [PATCH] Add device type power source. Closes https://github.com/espressif/esp-matter/issues/499 --- .../esp_matter/esp_matter_attribute.cpp | 279 ++++++++++++++++++ components/esp_matter/esp_matter_attribute.h | 41 +++ components/esp_matter/esp_matter_cluster.cpp | 58 +++- components/esp_matter/esp_matter_cluster.h | 16 + components/esp_matter/esp_matter_endpoint.cpp | 45 +++ components/esp_matter/esp_matter_endpoint.h | 13 + components/esp_matter/esp_matter_feature.cpp | 116 ++++++++ components/esp_matter/esp_matter_feature.h | 57 ++++ 8 files changed, 617 insertions(+), 8 deletions(-) diff --git a/components/esp_matter/esp_matter_attribute.cpp b/components/esp_matter/esp_matter_attribute.cpp index 29047952e..39ded270a 100644 --- a/components/esp_matter/esp_matter_attribute.cpp +++ b/components/esp_matter/esp_matter_attribute.cpp @@ -2225,5 +2225,284 @@ attribute_t *create_on_mode(cluster_t *cluster, nullable value) } /* attribute */ } /* mode_select */ +namespace power_source { +namespace attribute { + +attribute_t *create_status(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::Status::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); +} + +attribute_t *create_order(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::Order::Id, ATTRIBUTE_FLAG_NONVOLATILE, esp_matter_uint8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint8(min), esp_matter_uint8(max)); + return attribute; +} + +attribute_t *create_description(cluster_t *cluster, const char * value, uint16_t length) +{ + if (length > k_max_description_length) { + ESP_LOGE(TAG, "Could not create attribute, string length out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::Description::Id, ATTRIBUTE_FLAG_NONE, esp_matter_char_str((char *)value, length)); +} + +attribute_t *create_wired_assessed_input_voltage(cluster_t *cluster, nullable value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredAssessedInputVoltage::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_wired_assessed_input_frequency(cluster_t *cluster, nullable value, uint16_t min, uint16_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredAssessedInputFrequency::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint16(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint16(min), esp_matter_uint16(max)); + return attribute; +} + +attribute_t *create_wired_current_type(cluster_t *cluster, const uint8_t value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredCurrentType::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); +} + +attribute_t *create_wired_assessed_current(cluster_t *cluster, nullable value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredAssessedCurrent::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_wired_nominal_voltage(cluster_t *cluster, const uint32_t value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredNominalVoltage::Id, ATTRIBUTE_FLAG_NONE, esp_matter_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_wired_maximum_current(cluster_t *cluster, const uint32_t value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredMaximumCurrent::Id, ATTRIBUTE_FLAG_NONE, esp_matter_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_wired_present(cluster_t *cluster, bool value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::WiredPresent::Id, ATTRIBUTE_FLAG_NONE, esp_matter_bool(value)); +} + +attribute_t *create_active_wired_faults(cluster_t *cluster, uint8_t * value, uint16_t length, uint16_t count) +{ + if (count > k_max_fault_count) { + ESP_LOGE(TAG, "Could not create attribute, list out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::ActiveWiredFaults::Id, ATTRIBUTE_FLAG_NONE, esp_matter_array(value, length, count)); +} + +attribute_t *create_bat_voltage(cluster_t *cluster, nullable value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatVoltage::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_bat_percent_remaining(cluster_t *cluster, nullable value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatPercentRemaining::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint8(min), esp_matter_uint8(max)); + return attribute; +} + +attribute_t *create_bat_time_remaining(cluster_t *cluster, nullable value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatTimeRemaining::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_bat_charge_level(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatChargeLevel::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); +} + +attribute_t *create_bat_replacement_needed(cluster_t *cluster, bool value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatReplacementNeeded::Id, ATTRIBUTE_FLAG_NONE, esp_matter_bool(value)); +} + +attribute_t *create_bat_replaceability(cluster_t *cluster, const uint8_t value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatReplaceability::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); +} + +attribute_t *create_bat_present(cluster_t *cluster, bool value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatPresent::Id, ATTRIBUTE_FLAG_NONE, esp_matter_bool(value)); +} + +attribute_t *create_active_bat_faults(cluster_t *cluster, uint8_t * value, uint16_t length, uint16_t count) +{ + if (count > k_max_fault_count) { + ESP_LOGE(TAG, "Could not create attribute, list out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::ActiveBatFaults::Id, ATTRIBUTE_FLAG_NONE, esp_matter_array(value, length, count)); +} + +attribute_t *create_bat_replacement_description(cluster_t *cluster, const char * value, uint16_t length) +{ + if (length > k_max_description_length) { + ESP_LOGE(TAG, "Could not create attribute, string size out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatReplacementDescription::Id, ATTRIBUTE_FLAG_NONE, esp_matter_char_str((char *)value, length)); +} + +attribute_t *create_bat_common_designation(cluster_t *cluster, const uint8_t value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatCommonDesignation::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_enum8(min), esp_matter_enum8(max)); + return attribute; +} + +attribute_t *create_bat_ansi_designation(cluster_t *cluster, const char * value, uint16_t length) +{ + if (length > k_max_designation_count) { + ESP_LOGE(TAG, "Could not create attribute, string size out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatANSIDesignation::Id, ATTRIBUTE_FLAG_NONE, esp_matter_char_str((char *)value, length)); +} + +attribute_t *create_bat_iec_designation(cluster_t *cluster, const char * value, uint16_t length) +{ + if (length > k_max_designation_count) { + ESP_LOGE(TAG, "Could not create attribute, string size out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatIECDesignation::Id, ATTRIBUTE_FLAG_NONE, esp_matter_char_str((char *)value, length)); +} + +attribute_t *create_bat_approved_chemistry(cluster_t *cluster, const uint8_t value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatApprovedChemistry::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_enum8(min), esp_matter_enum8(max)); + return attribute; +} + +attribute_t *create_bat_capacity(cluster_t *cluster, const uint32_t value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatCapacity::Id, ATTRIBUTE_FLAG_NONE, esp_matter_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_bat_quantity(cluster_t *cluster, const uint8_t value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatQuantity::Id, ATTRIBUTE_FLAG_NONE, esp_matter_uint8(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint8(min), esp_matter_uint8(max)); + return attribute; +} + +attribute_t *create_bat_charge_state(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatChargeState::Id, ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); +} + +attribute_t *create_bat_time_to_full_charge(cluster_t *cluster, nullable value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatTimeToFullCharge::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_bat_functional_while_charging(cluster_t *cluster, bool value) +{ + return esp_matter::attribute::create(cluster, PowerSource::Attributes::BatFunctionalWhileCharging::Id, ATTRIBUTE_FLAG_NONE, esp_matter_bool(value)); +} + +attribute_t *create_bat_charging_current(cluster_t *cluster, nullable value, uint32_t min, uint32_t max) +{ + attribute_t *attribute = esp_matter::attribute::create(cluster, PowerSource::Attributes::BatChargingCurrent::Id, ATTRIBUTE_FLAG_NULLABLE, esp_matter_nullable_uint32(value)); + if (!attribute) { + ESP_LOGE(TAG, "Could not create attribute"); + return NULL; + } + esp_matter::attribute::add_bounds(attribute, esp_matter_uint32(min), esp_matter_uint32(max)); + return attribute; +} + +attribute_t *create_active_bat_charge_faults(cluster_t *cluster, uint8_t * value, uint16_t length, uint16_t count) +{ + if (count > k_max_charge_faults_count) { + ESP_LOGE(TAG, "Could not create attribute, list out of bound"); + return NULL; + } + return esp_matter::attribute::create(cluster, PowerSource::Attributes::ActiveBatChargeFaults::Id, ATTRIBUTE_FLAG_NONE, esp_matter_array(value, length, count)); +} + +} /* attribute */ +} /* power_source */ + } /* cluster */ } /* esp_matter */ diff --git a/components/esp_matter/esp_matter_attribute.h b/components/esp_matter/esp_matter_attribute.h index e7e916567..481d59d92 100644 --- a/components/esp_matter/esp_matter_attribute.h +++ b/components/esp_matter/esp_matter_attribute.h @@ -540,5 +540,46 @@ attribute_t *create_on_mode(cluster_t *cluster, nullable value); } /* attribute */ } /* mode_select */ +namespace power_source { +constexpr uint8_t k_max_description_length = 60; +constexpr uint8_t k_max_fault_count = 8; +constexpr uint8_t k_max_designation_count = 20; +constexpr uint8_t k_max_charge_faults_count = 16; + +namespace attribute { +attribute_t *create_status(cluster_t *cluster, uint8_t value); +attribute_t *create_order(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max); +attribute_t *create_description(cluster_t *cluster, const char * value, uint16_t length); +attribute_t *create_wired_assessed_input_voltage(cluster_t *cluster, nullable value, uint32_t min, uint32_t max); +attribute_t *create_wired_assessed_input_frequency(cluster_t *cluster, nullable value, uint16_t min, uint16_t max); +attribute_t *create_wired_current_type(cluster_t *cluster, const uint8_t value); +attribute_t *create_wired_assessed_current(cluster_t *cluster, nullable value, uint32_t min, uint32_t max); +attribute_t *create_wired_nominal_voltage(cluster_t *cluster, const uint32_t value, uint32_t min, uint32_t max); +attribute_t *create_wired_maximum_current(cluster_t *cluster, const uint32_t value, uint32_t min, uint32_t max); +attribute_t *create_wired_present(cluster_t *cluster, bool value); +attribute_t *create_active_wired_faults(cluster_t *cluster, uint8_t * value, uint16_t length, uint16_t count); +attribute_t *create_bat_voltage(cluster_t *cluster, nullable value, uint32_t min, uint32_t max); +attribute_t *create_bat_percent_remaining(cluster_t *cluster, nullable value, uint8_t min, uint8_t max); +attribute_t *create_bat_time_remaining(cluster_t *cluster, nullable< uint32_t> value, uint32_t min, uint32_t max); +attribute_t *create_bat_charge_level(cluster_t *cluster, uint8_t value); +attribute_t *create_bat_replacement_needed(cluster_t *cluster, bool value); +attribute_t *create_bat_replaceability(cluster_t *cluster, const uint8_t value); +attribute_t *create_bat_present(cluster_t *cluster, bool value); +attribute_t *create_active_bat_faults(cluster_t *cluster, uint8_t * value, uint16_t length, uint16_t count); +attribute_t *create_bat_replacement_description(cluster_t *cluster, const char * value, uint16_t length); +attribute_t *create_bat_common_designation(cluster_t *cluster, const uint8_t value, uint8_t min, uint8_t max); +attribute_t *create_bat_ansi_designation(cluster_t *cluster, const char * value, uint16_t length); +attribute_t *create_bat_iec_designation(cluster_t *cluster, const char * value, uint16_t length); +attribute_t *create_bat_approved_chemistry(cluster_t *cluster, const uint8_t value, uint8_t min, uint8_t max); +attribute_t *create_bat_capacity(cluster_t *cluster, const uint32_t value, uint32_t min, uint32_t max); +attribute_t *create_bat_quantity(cluster_t *cluster, const uint8_t value, uint8_t min, uint8_t max); +attribute_t *create_bat_charge_state(cluster_t *cluster, uint8_t value); +attribute_t *create_bat_time_to_full_charge(cluster_t *cluster, nullable value, uint32_t min, uint32_t max); +attribute_t *create_bat_functional_while_charging(cluster_t *cluster, bool value); +attribute_t *create_bat_charging_current(cluster_t *cluster, nullable value, uint32_t min, uint32_t max); +attribute_t *create_active_bat_charge_faults(cluster_t *cluster, uint8_t * value, uint16_t length, uint16_t count); +} /* attribute */ +} /* power_source */ + } /* cluster */ } /* esp_matter */ diff --git a/components/esp_matter/esp_matter_cluster.cpp b/components/esp_matter/esp_matter_cluster.cpp index 8180685c7..cba88c456 100644 --- a/components/esp_matter/esp_matter_cluster.cpp +++ b/components/esp_matter/esp_matter_cluster.cpp @@ -765,6 +765,55 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) } } /* bridged_device_basic_information */ +namespace power_source { +const function_generic_t *function_list = NULL; +const int function_flags = CLUSTER_FLAG_NONE; + +cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_t features) +{ + cluster_t *cluster = cluster::create(endpoint, PowerSource::Id, flags); + if (!cluster) { + ESP_LOGE(TAG, "Could not create cluster"); + return NULL; + } + if (flags & CLUSTER_FLAG_SERVER) { + set_plugin_server_init_callback(cluster, MatterPowerSourcePluginServerInitCallback); + add_function_list(cluster, function_list, function_flags); + + /* Attributes managed internally */ + global::attribute::create_feature_map(cluster, 0); + /** Attributes not managed internally **/ + if (config) { + global::attribute::create_cluster_revision(cluster, config->cluster_revision); + attribute::create_status(cluster, config->status); + attribute::create_order(cluster, config->order, 0x00, 0xFF); + attribute::create_description(cluster, config->description, sizeof(config->description)); + } else { + ESP_LOGE(TAG, "Config is NULL. Cannot add some attributes."); + } + } + + /* Features */ + if (features & feature::wired::get_id()) { + feature::wired::add(cluster, &(config->wired)); + } + + if (features & feature::battery::get_id()) { + feature::battery::add(cluster, &(config->battery)); + } + + if (features & feature::rechargeable::get_id()) { + feature::rechargeable::add(cluster, &(config->rechargeable)); + } + + if (features & feature::replaceable::get_id()) { + feature::replaceable::add(cluster, &(config->replaceable)); + } + + return cluster; +} +} /* power_source */ + namespace user_label { const function_generic_t *function_list = NULL; const int function_flags = CLUSTER_FLAG_NONE; @@ -1899,6 +1948,7 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_ } } /* software_diagnostics */ + // namespace binary_input_basic { // // ToDo // } /* binary_input_basic */ @@ -1915,10 +1965,6 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_ // // ToDo // } /* powersource_configuration */ -// namespace powersource { -// // ToDo -// } /* powersource */ - // namespace ethernet_network_diagnostics { // // ToDo // } /* ethernet_network_diagnostics */ @@ -1935,10 +1981,6 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_ // // ToDo // } /* proxy_valid */ -// namespace mode_select { -// // ToDo -// } /* mode_select */ - // namespace barrier_control { // // ToDo // } /* barrier_control */ diff --git a/components/esp_matter/esp_matter_cluster.h b/components/esp_matter/esp_matter_cluster.h index 38c2f6955..d28c3143e 100644 --- a/components/esp_matter/esp_matter_cluster.h +++ b/components/esp_matter/esp_matter_cluster.h @@ -197,6 +197,22 @@ typedef struct config { cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags); } /* bridged_device_basic_information */ +namespace power_source { +typedef struct config { + uint16_t cluster_revision; + uint8_t status; + uint8_t order; + char description[61]; + feature::wired::config_t wired; + feature::battery::config_t battery; + feature::rechargeable::config_t rechargeable; + feature::replaceable::config_t replaceable; + config() : cluster_revision(1), status(0), order(0), description{0} {} +} config_t; + +cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags, uint32_t features); +} /* power_source */ + namespace user_label { typedef struct config { uint16_t cluster_revision; diff --git a/components/esp_matter/esp_matter_endpoint.cpp b/components/esp_matter/esp_matter_endpoint.cpp index d30168330..b1030bfcf 100644 --- a/components/esp_matter/esp_matter_endpoint.cpp +++ b/components/esp_matter/esp_matter_endpoint.cpp @@ -68,6 +68,51 @@ endpoint_t *add(endpoint_t *endpoint, config_t *config) } } /* root_node */ +namespace power_source_device{ +uint32_t get_device_type_id() +{ + return ESP_MATTER_POWER_SOURCE_DEVICE_TYPE_ID; +} + +uint8_t get_device_type_version() +{ + return ESP_MATTER_POWER_SOURCE_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); + if (endpoint) { + return add(endpoint, config); + } + return endpoint; +} + +endpoint_t *add(endpoint_t *endpoint, config_t *config) +{ + if (!endpoint) { + ESP_LOGE(TAG, "Could not create endpoint"); + return NULL; + } + esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version()); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to add device type: err: %d", err); + } + + cluster_t *cluster = descriptor::create(endpoint, CLUSTER_FLAG_SERVER); + if (!cluster) { + return NULL; + } + cluster = power_source::create(endpoint, &(config->power_source), CLUSTER_FLAG_SERVER, ESP_MATTER_NONE_FEATURE_ID); + if (!cluster) { + return NULL; + } + + return endpoint; +} + +} /** power_source_device **/ + namespace on_off_light { uint32_t get_device_type_id() { diff --git a/components/esp_matter/esp_matter_endpoint.h b/components/esp_matter/esp_matter_endpoint.h index 3c3e4aada..9d40365a5 100644 --- a/components/esp_matter/esp_matter_endpoint.h +++ b/components/esp_matter/esp_matter_endpoint.h @@ -21,6 +21,8 @@ /* Replace these with IDs from submodule whenever they are implemented */ #define ESP_MATTER_ROOT_NODE_DEVICE_TYPE_ID 0x0016 #define ESP_MATTER_ROOT_NODE_DEVICE_TYPE_VERSION 1 +#define ESP_MATTER_POWER_SOURCE_DEVICE_TYPE_ID 0x0011 +#define ESP_MATTER_POWER_SOURCE_DEVICE_TYPE_VERSION 1 #define ESP_MATTER_AGGREGATOR_DEVICE_TYPE_ID 0x000E #define ESP_MATTER_AGGREGATOR_DEVICE_TYPE_VERSION 1 #define ESP_MATTER_BRIDGED_NODE_DEVICE_TYPE_ID 0x0013 @@ -107,6 +109,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); } /* root_node */ +namespace power_source_device{ +typedef struct config { + cluster::power_source::config_t power_source; +} 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); +} /* power_source_device */ + namespace on_off_light { typedef struct config { cluster::identify::config_t identify; diff --git a/components/esp_matter/esp_matter_feature.cpp b/components/esp_matter/esp_matter_feature.cpp index 21b58ec3c..172f5d195 100644 --- a/components/esp_matter/esp_matter_feature.cpp +++ b/components/esp_matter/esp_matter_feature.cpp @@ -63,6 +63,122 @@ static uint32_t get_feature_map_value(cluster_t *cluster) return val.val.u32; } +namespace power_source { +namespace feature { +namespace wired { + +uint32_t get_id() +{ + return (uint32_t)PowerSource::Feature::kWired; +} + +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()); + + /* Attributes not managed internally */ + attribute::create_wired_current_type(cluster, config->wired_current_type); + + return ESP_OK; +} + +} /* wired */ + +namespace battery { + +uint32_t get_id() +{ + return (uint32_t)PowerSource::Feature::kBattery; +} + +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()); + + /* Attributes not managed internally */ + attribute::create_bat_charge_level(cluster, config->bat_charge_level); + attribute::create_bat_replacement_needed(cluster, config->bat_replacement_needed); + attribute::create_bat_replaceability(cluster, config->bat_replaceability); + + return ESP_OK; +} + +} /* battery */ + +namespace rechargeable { + +uint32_t get_id() +{ + return (uint32_t)PowerSource::Feature::kRechargeable; +} + +esp_err_t add(cluster_t *cluster, config_t *config) +{ + if (!cluster) { + ESP_LOGE(TAG, "Cluster cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + + uint32_t battery_feature_map = feature::battery::get_id(); + if((get_feature_map_value(cluster) & battery_feature_map) == battery_feature_map) { + + update_feature_map(cluster, get_id()); + + /* Attributes not managed internally */ + attribute::create_bat_charge_state(cluster, config->bat_charge_state); + attribute::create_bat_functional_while_charging(cluster, config->bat_functional_while_charging); + } else { + ESP_LOGE(TAG, "Cluster shall support Battery feature"); + return ESP_ERR_NOT_SUPPORTED; + } + + return ESP_OK; +} + +} /* rechargeable */ + +namespace replaceable { + +uint32_t get_id() +{ + return (uint32_t)PowerSource::Feature::kReplaceable; +} + +esp_err_t add(cluster_t *cluster, config_t *config) +{ + if (!cluster) { + ESP_LOGE(TAG, "Cluster cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + + uint32_t battery_feature_map = feature::battery::get_id(); + if((get_feature_map_value(cluster) & battery_feature_map) == battery_feature_map) { + + update_feature_map(cluster, get_id()); + + /* Attributes not managed internally */ + attribute::create_bat_replacement_description(cluster, config->bat_replacement_description, sizeof(config->bat_replacement_description)); + attribute::create_bat_quantity(cluster, config->bat_quantity, 0, 255); + } else { + ESP_LOGE(TAG, "Cluster shall support Battery feature"); + return ESP_ERR_NOT_SUPPORTED; + } + + return ESP_OK; +} + +} /* replaceable */ +} /* feature */ +} /* power_source */ + namespace on_off { namespace feature { namespace lighting { diff --git a/components/esp_matter/esp_matter_feature.h b/components/esp_matter/esp_matter_feature.h index 06185b671..02e7a7412 100644 --- a/components/esp_matter/esp_matter_feature.h +++ b/components/esp_matter/esp_matter_feature.h @@ -31,6 +31,63 @@ namespace esp_matter { namespace cluster { +namespace power_source { +namespace feature { +namespace wired { +typedef struct config { + uint8_t wired_current_type; + config(): wired_current_type(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); + +} /* wired */ + +namespace battery { +typedef struct config { + uint8_t bat_charge_level; + bool bat_replacement_needed; + uint8_t bat_replaceability; + config(): bat_charge_level(0), bat_replacement_needed(false), bat_replaceability(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); + +} /* battery */ + +// Rechargeable feature is dependent on Battery feature, inorder to add +// Rechargeable feature one must add Battery feature first. +namespace rechargeable { +typedef struct config { + uint8_t bat_charge_state; + bool bat_functional_while_charging; + config(): bat_charge_state(0), bat_functional_while_charging(false) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); + +} /* rechargeable */ + +// Replaceable feature is dependent on Battery feature, inorder to add +// Replaceable feature one must add Battery feature first. +namespace replaceable { +typedef struct config { + char bat_replacement_description[61]; + uint8_t bat_quantity; + config(): bat_replacement_description{0}, bat_quantity(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); + +} /* replaceable */ + +} /* feature */ +} /* power_source */ + namespace on_off { namespace feature { namespace lighting {