From 08a2f751df8a0619cf06cb2c4418df90bd1baa23 Mon Sep 17 00:00:00 2001 From: Rohit Jadhav Date: Tue, 1 Aug 2023 14:33:23 +0530 Subject: [PATCH] Sync fan control cluster impl to spec --- .../esp_matter/esp_matter_attribute.cpp | 71 +++++++++- components/esp_matter/esp_matter_attribute.h | 10 +- components/esp_matter/esp_matter_cluster.h | 2 +- components/esp_matter/esp_matter_command.cpp | 21 +++ components/esp_matter/esp_matter_command.h | 6 + components/esp_matter/esp_matter_feature.cpp | 134 ++++++++++++++++++ components/esp_matter/esp_matter_feature.h | 63 ++++++++ 7 files changed, 303 insertions(+), 4 deletions(-) diff --git a/components/esp_matter/esp_matter_attribute.cpp b/components/esp_matter/esp_matter_attribute.cpp index b8468ac93..38fd8627b 100644 --- a/components/esp_matter/esp_matter_attribute.cpp +++ b/components/esp_matter/esp_matter_attribute.cpp @@ -1224,10 +1224,10 @@ attribute_t *create_fan_mode(cluster_t *cluster, uint8_t value, uint8_t min, uin return attribute; } -attribute_t *create_fan_mode_sequence(cluster_t *cluster, uint8_t value) +attribute_t *create_fan_mode_sequence(cluster_t *cluster, const uint8_t value) { return esp_matter::attribute::create(cluster, FanControl::Attributes::FanModeSequence::Id, - ATTRIBUTE_FLAG_NONVOLATILE | ATTRIBUTE_FLAG_WRITABLE, esp_matter_enum8(value)); + ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value)); } attribute_t *create_percent_setting(cluster_t *cluster, nullable value) @@ -1243,6 +1243,73 @@ attribute_t *create_percent_current(cluster_t *cluster, uint8_t value) esp_matter_uint8(value)); } +attribute_t *create_speed_max(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = + esp_matter::attribute::create(cluster, FanControl::Attributes::SpeedMax::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_speed_setting(cluster_t *cluster, nullable value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = + esp_matter::attribute::create(cluster, FanControl::Attributes::SpeedSetting::Id, + ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_WRITABLE, 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_speed_current(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max) +{ + attribute_t *attribute = + esp_matter::attribute::create(cluster, FanControl::Attributes::SpeedCurrent::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_rock_support(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, FanControl::Attributes::RockSupport::Id, ATTRIBUTE_FLAG_NONE, + esp_matter_bitmap8(value)); +} + +attribute_t *create_rock_setting(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, FanControl::Attributes::RockSetting::Id, ATTRIBUTE_FLAG_WRITABLE, + esp_matter_bitmap8(value)); +} + +attribute_t *create_wind_support(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, FanControl::Attributes::WindSupport::Id, ATTRIBUTE_FLAG_NONE, + esp_matter_bitmap8(value)); +} + +attribute_t *create_wind_setting(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, FanControl::Attributes::WindSetting::Id, ATTRIBUTE_FLAG_WRITABLE, + esp_matter_bitmap8(value)); +} + +attribute_t *create_airflow_direction(cluster_t *cluster, uint8_t value) +{ + return esp_matter::attribute::create(cluster, FanControl::Attributes::AirflowDirection::Id, ATTRIBUTE_FLAG_WRITABLE, + esp_matter_enum8(value)); +} + } /* attribute */ } /* fan_control */ diff --git a/components/esp_matter/esp_matter_attribute.h b/components/esp_matter/esp_matter_attribute.h index 7bc6054c5..a488fca5a 100644 --- a/components/esp_matter/esp_matter_attribute.h +++ b/components/esp_matter/esp_matter_attribute.h @@ -316,9 +316,17 @@ attribute_t *create_primary_n_intensity(cluster_t * cluster, nullable v namespace fan_control { namespace attribute { attribute_t *create_fan_mode(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max); -attribute_t *create_fan_mode_sequence(cluster_t *cluster, uint8_t value); +attribute_t *create_fan_mode_sequence(cluster_t *cluster, const uint8_t value); attribute_t *create_percent_setting(cluster_t *cluster, nullable value); attribute_t *create_percent_current(cluster_t *cluster, uint8_t value); +attribute_t *create_speed_max(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max); +attribute_t *create_speed_setting(cluster_t *cluster, nullable value, uint8_t min, uint8_t max); +attribute_t *create_speed_current(cluster_t *cluster, uint8_t value, uint8_t min, uint8_t max); +attribute_t *create_rock_support(cluster_t *cluster, uint8_t value); +attribute_t *create_rock_setting(cluster_t *cluster, uint8_t value); +attribute_t *create_wind_support(cluster_t *cluster, uint8_t value); +attribute_t *create_wind_setting(cluster_t *cluster, uint8_t value); +attribute_t *create_airflow_direction(cluster_t *cluster, uint8_t value); } /* attribute */ } /* fan_control */ diff --git a/components/esp_matter/esp_matter_cluster.h b/components/esp_matter/esp_matter_cluster.h index 2209d01f3..33d0f1809 100644 --- a/components/esp_matter/esp_matter_cluster.h +++ b/components/esp_matter/esp_matter_cluster.h @@ -318,7 +318,7 @@ typedef struct config { uint8_t fan_mode_sequence; nullable percent_setting; uint8_t percent_current; - config() : cluster_revision(2), fan_mode(0), fan_mode_sequence(2), percent_setting(0), percent_current(0) {} + config() : cluster_revision(4), fan_mode(0), fan_mode_sequence(2), percent_setting(0), percent_current(0) {} } config_t; cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags); diff --git a/components/esp_matter/esp_matter_command.cpp b/components/esp_matter/esp_matter_command.cpp index 998d6699b..965db4ad7 100644 --- a/components/esp_matter/esp_matter_command.cpp +++ b/components/esp_matter/esp_matter_command.cpp @@ -1017,6 +1017,16 @@ static esp_err_t esp_matter_command_callback_set_temperature(const ConcreteComma return ESP_OK; } +static esp_err_t esp_matter_command_callback_fan_step(const ConcreteCommandPath &command_path, TLVReader &tlv_data, void *opaque_ptr) +{ + chip::app::Clusters::FanControl::Commands::Step::DecodableType command_data; + CHIP_ERROR error = Decode(tlv_data, command_data); + if (error == CHIP_NO_ERROR) { + emberAfFanControlClusterStepCallback((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) { @@ -2091,6 +2101,17 @@ command_t *create_set_temperature(cluster_t *cluster) } /* command */ } /* temperature_control */ +namespace fan_control { +namespace command { +command_t *create_step(cluster_t *cluster) +{ + return esp_matter::command::create(cluster, FanControl::Commands::Step::Id, COMMAND_FLAG_ACCEPTED, + esp_matter_command_callback_fan_step); +} + +} /* command */ +} /* fan_control */ + } /* cluster */ } /* esp_matter */ diff --git a/components/esp_matter/esp_matter_command.h b/components/esp_matter/esp_matter_command.h index c7f81a7a4..41c337ab2 100644 --- a/components/esp_matter/esp_matter_command.h +++ b/components/esp_matter/esp_matter_command.h @@ -280,5 +280,11 @@ command_t *create_set_temperature(cluster_t *cluster); } /* command */ } /* temperature_control */ +namespace fan_control { +namespace command { +command_t *create_step(cluster_t *cluster); +} /* command */ +} /* fan_control */ + } /* cluster */ } /* esp_matter */ diff --git a/components/esp_matter/esp_matter_feature.cpp b/components/esp_matter/esp_matter_feature.cpp index e7f98c97e..33b427e1c 100644 --- a/components/esp_matter/esp_matter_feature.cpp +++ b/components/esp_matter/esp_matter_feature.cpp @@ -1281,5 +1281,139 @@ esp_err_t add(cluster_t *cluster, config_t *config) } /* feature */ } /* temperature_control */ +namespace fan_control { +namespace feature { + +namespace multi_speed { + +uint32_t get_id() +{ + return (uint32_t)FanControl::Feature::kMultiSpeed; +} + +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_speed_max(cluster, config->speed_max, 0, k_max_limit); + attribute::create_speed_setting(cluster, config->speed_setting, 0, config->speed_max); + attribute::create_speed_current(cluster, config->speed_current, 0, config->speed_max); + + return ESP_OK; +} +} /* multi_speed */ + +namespace fan_auto { + +uint32_t get_id() +{ + return (uint32_t)FanControl::Feature::kAuto; +} + +esp_err_t add(cluster_t *cluster) +{ + if (!cluster) { + ESP_LOGE(TAG, "Cluster cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + update_feature_map(cluster, get_id()); + + return ESP_OK; +} +} /* fan_auto */ + +namespace rocking { + +uint32_t get_id() +{ + return (uint32_t)FanControl::Feature::kRocking; +} + +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_rock_support(cluster, config->rock_support); + attribute::create_rock_setting(cluster, config->rock_setting); + + return ESP_OK; +} +} /* rocking */ + +namespace wind { + +uint32_t get_id() +{ + return (uint32_t)FanControl::Feature::kWind; +} + +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_wind_support(cluster, config->wind_support); + attribute::create_wind_setting(cluster, config->wind_setting); + + return ESP_OK; +} +} /* wind */ + +namespace step { + +uint32_t get_id() +{ + return (uint32_t)FanControl::Feature::kStep; +} + +esp_err_t add(cluster_t *cluster) +{ + if (!cluster) { + ESP_LOGE(TAG, "Cluster cannot be NULL"); + return ESP_ERR_INVALID_ARG; + } + update_feature_map(cluster, get_id()); + + command::create_step(cluster); + + return ESP_OK; +} +} /* step */ + +namespace airflow_direction { + +uint32_t get_id() +{ + return (uint32_t)FanControl::Feature::kAirflowDirection; +} + +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_airflow_direction(cluster, config->airflow_direction); + + return ESP_OK; +} +} /* airflow_direction */ + +} /* feature */ +} /* fan_control */ + } /* cluster */ } /* esp_matter */ diff --git a/components/esp_matter/esp_matter_feature.h b/components/esp_matter/esp_matter_feature.h index 59cc80bb5..f40d8556f 100644 --- a/components/esp_matter/esp_matter_feature.h +++ b/components/esp_matter/esp_matter_feature.h @@ -569,5 +569,68 @@ esp_err_t add(cluster_t *cluster, config_t *config); } /* feature */ } /* temperature_control */ +namespace fan_control { +namespace feature { + +namespace multi_speed { +constexpr uint32_t k_max_limit = 100; +typedef struct config { + uint8_t speed_max; + nullable speed_setting; + uint8_t speed_current; + config() : speed_max(10), speed_setting(0), speed_current(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); +} /* multi_speed */ + +namespace fan_auto { + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster); +} /* fan_auto */ + +namespace rocking { +typedef struct config { + uint8_t rock_support; + uint8_t rock_setting; + config() : rock_support(0), rock_setting(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); +} /* rocking */ + +namespace wind { +typedef struct config { + uint8_t wind_support; + uint8_t wind_setting; + config() : wind_support(0), wind_setting(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); +} /* wind */ + +namespace step { + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster); +} /* step */ + +namespace airflow_direction { +typedef struct config { + uint8_t airflow_direction; + config() : airflow_direction(0) {} +} config_t; + +uint32_t get_id(); +esp_err_t add(cluster_t *cluster, config_t *config); +} /* airflow_direction */ + +} /* feature */ +} /* fan_control */ + } /* cluster */ } /* esp_matter */