Merge branch 'time-sync' into 'main'

esp_matter: add missing attributes and commands for time sync cluster

See merge request app-frameworks/esp-matter!990
This commit is contained in:
Hrishikesh Dhayagude
2024-12-27 13:27:05 +08:00
8 changed files with 402 additions and 0 deletions
@@ -5028,5 +5028,94 @@ attribute_t *create_location_directory(cluster_t *cluster, uint8_t *value, uint1
} /* attribute */
} /* ecosystem_information */
namespace time_synchronization {
namespace attribute {
attribute_t *create_utc_time(cluster_t *cluster, nullable<uint64_t> value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::UTCTime::Id,
ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_MANAGED_INTERNALLY,
esp_matter_nullable_uint64(value));
}
attribute_t *create_granularity(cluster_t *cluster, uint8_t value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::Granularity::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY, esp_matter_enum8(value));
}
attribute_t *create_time_source(cluster_t *cluster, uint8_t value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::TimeSource::Id,
ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value));
}
attribute_t *create_trusted_time_source(cluster_t *cluster, uint8_t *value, uint16_t length, uint16_t count)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::TrustedTimeSource::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY | ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_NONVOLATILE,
esp_matter_array(value, length, count));
}
attribute_t *create_default_ntp(cluster_t *cluster, char *value, uint16_t length)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::DefaultNTP::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY | ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_NONVOLATILE,
esp_matter_char_str(value, length));
}
attribute_t *create_time_zone(cluster_t *cluster, uint8_t *value, uint16_t length, uint16_t count)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::TimeZone::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY | ATTRIBUTE_FLAG_NONVOLATILE,
esp_matter_array(value, length, count));
}
attribute_t *create_dst_offset(cluster_t *cluster, uint8_t *value, uint16_t length, uint16_t count)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::DSTOffset::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY | ATTRIBUTE_FLAG_NONVOLATILE,
esp_matter_array(value, length, count));
}
attribute_t *create_local_time(cluster_t *cluster, nullable<uint64_t> value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::LocalTime::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY | ATTRIBUTE_FLAG_NULLABLE,
esp_matter_nullable_uint64(value));
}
attribute_t *create_time_zone_database(cluster_t *cluster, uint8_t value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::TimeZoneDatabase::Id,
ATTRIBUTE_FLAG_NONE, esp_matter_enum8(value));
}
attribute_t *create_ntp_server_available(cluster_t *cluster, bool value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::NTPServerAvailable::Id,
ATTRIBUTE_FLAG_NONE, esp_matter_bool(value));
}
attribute_t *create_time_zone_list_max_size(cluster_t *cluster, uint8_t value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::TimeZoneListMaxSize::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY, esp_matter_uint8(value));
}
attribute_t *create_dst_offset_list_max_size(cluster_t *cluster, uint8_t value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::DSTOffsetListMaxSize::Id,
ATTRIBUTE_FLAG_MANAGED_INTERNALLY, esp_matter_uint8(value));
}
attribute_t *create_supports_dns_resolve(cluster_t *cluster, bool value)
{
return esp_matter::attribute::create(cluster, TimeSynchronization::Attributes::SupportsDNSResolve::Id,
ATTRIBUTE_FLAG_NONE, esp_matter_uint64(value));
}
} /* attribute */
} /* time_synchronization */
} /* cluster */
} /* esp_matter */
@@ -1245,5 +1245,23 @@ attribute_t *create_location_directory(cluster_t *cluster, uint8_t *value, uint1
} /* attribute */
} /* ecosystem_information */
namespace time_synchronization {
namespace attribute {
attribute_t *create_utc_time(cluster_t *cluster, nullable<uint64_t> value);
attribute_t *create_granularity(cluster_t *cluster, uint8_t value);
attribute_t *create_time_source(cluster_t *cluster, uint8_t value);
attribute_t *create_trusted_time_source(cluster_t *cluster, uint8_t *value, uint16_t length, uint16_t count);
attribute_t *create_default_ntp(cluster_t *cluster, char *value, uint16_t length);
attribute_t *create_time_zone(cluster_t *cluster, uint8_t *value, uint16_t length, uint16_t count);
attribute_t *create_dst_offset(cluster_t *cluster, uint8_t *value, uint16_t length, uint16_t count);
attribute_t *create_local_time(cluster_t *cluster, nullable<uint64_t> value);
attribute_t *create_time_zone_database(cluster_t *cluster, uint8_t value);
attribute_t *create_ntp_server_available(cluster_t *cluster, bool value);
attribute_t *create_time_zone_list_max_size(cluster_t *cluster, uint8_t value);
attribute_t *create_dst_offset_list_max_size(cluster_t *cluster, uint8_t value);
attribute_t *create_supports_dns_resolve(cluster_t *cluster, bool value);
} /* attribute */
} /* time_synchronization */
} /* cluster */
} /* esp_matter */
@@ -679,9 +679,14 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags)
/* Attributes managed internally */
global::attribute::create_feature_map(cluster, 0);
attribute::create_utc_time(cluster, nullable<uint64_t>());
attribute::create_granularity(cluster, 0);
/* Attributes not managed internally */
global::attribute::create_cluster_revision(cluster, cluster_revision);
/* Commands */
command::create_set_utc_time(cluster);
}
event::create_time_failure(cluster);
@@ -1555,6 +1555,62 @@ static esp_err_t esp_matter_command_callback_close(const ConcreteCommandPath &co
return ESP_OK;
}
static esp_err_t esp_matter_command_callback_set_utc_time(const ConcreteCommandPath &command_path, TLVReader &tlv_data,
void *opaque_ptr)
{
chip::app::Clusters::TimeSynchronization::Commands::SetUTCTime::DecodableType command_data;
CHIP_ERROR error = Decode(tlv_data, command_data);
if (error == CHIP_NO_ERROR) {
emberAfTimeSynchronizationClusterSetUTCTimeCallback((CommandHandler *)opaque_ptr, command_path, command_data);
}
return ESP_OK;
}
static esp_err_t esp_matter_command_callback_set_trusted_time_source(const ConcreteCommandPath &command_path,
TLVReader &tlv_data, void *opaque_ptr)
{
chip::app::Clusters::TimeSynchronization::Commands::SetTrustedTimeSource::DecodableType command_data;
CHIP_ERROR error = Decode(tlv_data, command_data);
if (error == CHIP_NO_ERROR) {
emberAfTimeSynchronizationClusterSetTrustedTimeSourceCallback((CommandHandler *)opaque_ptr, command_path,
command_data);
}
return ESP_OK;
}
static esp_err_t esp_matter_command_callback_set_time_zone(const ConcreteCommandPath &command_path, TLVReader &tlv_data,
void *opaque_ptr)
{
chip::app::Clusters::TimeSynchronization::Commands::SetTimeZone::DecodableType command_data;
CHIP_ERROR error = Decode(tlv_data, command_data);
if (error == CHIP_NO_ERROR) {
emberAfTimeSynchronizationClusterSetTimeZoneCallback((CommandHandler *)opaque_ptr, command_path, command_data);
}
return ESP_OK;
}
static esp_err_t esp_matter_command_callback_set_dst_offset(const ConcreteCommandPath &command_path, TLVReader &tlv_data,
void *opaque_ptr)
{
chip::app::Clusters::TimeSynchronization::Commands::SetDSTOffset::DecodableType command_data;
CHIP_ERROR error = Decode(tlv_data, command_data);
if (error == CHIP_NO_ERROR) {
emberAfTimeSynchronizationClusterSetDSTOffsetCallback((CommandHandler *)opaque_ptr, command_path, command_data);
}
return ESP_OK;
}
static esp_err_t esp_matter_command_callback_set_default_ntp(const ConcreteCommandPath &command_path, TLVReader &tlv_data,
void *opaque_ptr)
{
chip::app::Clusters::TimeSynchronization::Commands::SetDefaultNTP::DecodableType command_data;
CHIP_ERROR error = Decode(tlv_data, command_data);
if (error == CHIP_NO_ERROR) {
emberAfTimeSynchronizationClusterSetDefaultNTPCallback((CommandHandler *)opaque_ptr, command_path, command_data);
}
return ESP_OK;
}
namespace esp_matter {
namespace cluster {
@@ -3451,6 +3507,53 @@ command_t *create_reverse_open_commissioning_window(cluster_t *cluster)
} /* command */
} /* commissioner_control */
namespace time_synchronization {
namespace command {
constexpr const command_entry_t accepted_command_list[] = {
{TimeSynchronization::Commands::SetUTCTime::Id, COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_set_utc_time},
};
constexpr const command_entry_t generated_command_list[] = {};
command_t *create_set_utc_time(cluster_t *cluster)
{
return esp_matter::command::create(cluster, TimeSynchronization::Commands::SetUTCTime::Id, COMMAND_FLAG_ACCEPTED,
esp_matter_command_callback_set_utc_time);
}
command_t *create_set_trusted_time_source(cluster_t *cluster)
{
return esp_matter::command::create(cluster, TimeSynchronization::Commands::SetTrustedTimeSource::Id,
COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_set_trusted_time_source);
}
command_t *create_set_time_zone(cluster_t *cluster)
{
return esp_matter::command::create(cluster, TimeSynchronization::Commands::SetTimeZone::Id, COMMAND_FLAG_ACCEPTED,
esp_matter_command_callback_set_time_zone);
}
command_t *create_set_time_zone_response(cluster_t *cluster)
{
return esp_matter::command::create(cluster, TimeSynchronization::Commands::SetTimeZoneResponse::Id,
COMMAND_FLAG_GENERATED, nullptr);
}
command_t *create_set_dst_offset(cluster_t *cluster)
{
return esp_matter::command::create(cluster, TimeSynchronization::Commands::SetDSTOffset::Id,
COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_set_dst_offset);
}
command_t *create_set_default_ntp(cluster_t *cluster)
{
return esp_matter::command::create(cluster, TimeSynchronization::Commands::SetDefaultNTP::Id,
COMMAND_FLAG_ACCEPTED, esp_matter_command_callback_set_default_ntp);
}
} /* command */
} /* time_synchronization */
} /* cluster */
} /* esp_matter */
@@ -3499,6 +3602,7 @@ constexpr const cluster_command_t cluster_command_table[] = {
{ThreadNetworkDirectory::Id, GET_COMMAND_COUNT_LIST(cluster::thread_network_directory)},
{WaterHeaterManagement::Id, GET_COMMAND_COUNT_LIST(cluster::water_heater_management)},
{CommissionerControl::Id, GET_COMMAND_COUNT_LIST(cluster::commissioner_control)},
{TimeSynchronization::Id, GET_COMMAND_COUNT_LIST(cluster::time_synchronization)},
};
#if defined(CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER) && defined(CONFIG_ESP_MATTER_ENABLE_DATA_MODEL)
@@ -503,5 +503,16 @@ command_t *create_reverse_open_commissioning_window(cluster_t *cluster);
} /* command */
} /* commissioner_control */
namespace time_synchronization {
namespace command {
command_t *create_set_utc_time(cluster_t *cluster);
command_t *create_set_trusted_time_source(cluster_t *cluster);
command_t *create_set_time_zone(cluster_t *cluster);
command_t *create_set_time_zone_response(cluster_t *cluster);
command_t *create_set_dst_offset(cluster_t *cluster);
command_t *create_set_default_ntp(cluster_t *cluster);
} /* command */
} /* time_synchronization */
} /* cluster */
} /* esp_matter */
@@ -4941,5 +4941,123 @@ esp_err_t add(cluster_t *cluster)
} /* feature */
} /* pump_configuration_and_control */
namespace time_synchronization {
namespace feature {
namespace time_zone {
uint32_t get_id()
{
return static_cast<uint32_t>(TimeSynchronization::Feature::kTimeZone);
}
esp_err_t add(cluster_t *cluster, config_t *config)
{
if (!cluster || !config) {
ESP_LOGE(TAG, "Cluster or config cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
update_feature_map(cluster, get_id());
// Attributes managed internally
attribute::create_time_zone(cluster, nullptr, 0, 0);
attribute::create_dst_offset(cluster, nullptr, 0, 0);
attribute::create_local_time(cluster, nullable<uint64_t>());
attribute::create_time_zone_list_max_size(cluster, 0);
attribute::create_dst_offset_list_max_size(cluster, 0);
// Attributes not managed internally
attribute::create_time_zone_database(cluster, config->time_zone_database);
// Commands
command::create_set_time_zone(cluster);
command::create_set_dst_offset(cluster);
command::create_set_time_zone_response(cluster);
// Events
event::create_dst_table_empty(cluster);
event::create_dst_status(cluster);
event::create_time_zone_status(cluster);
return ESP_OK;
}
} /* time_zone */
namespace ntp_client {
uint32_t get_id()
{
return static_cast<uint32_t>(TimeSynchronization::Feature::kNTPClient);
}
esp_err_t add(cluster_t *cluster, config_t *config)
{
if (!cluster || !config) {
ESP_LOGE(TAG, "Cluster or config cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
update_feature_map(cluster, get_id());
// Attributes managed internally
attribute::create_default_ntp(cluster, nullptr, 0);
// Attributes not managed internally
attribute::create_supports_dns_resolve(cluster, config->supports_dns_resolve);
// Commands
command::create_set_default_ntp(cluster);
return ESP_OK;
}
} /* ntp_client */
namespace ntp_server {
uint32_t get_id()
{
return static_cast<uint32_t>(TimeSynchronization::Feature::kNTPServer);
}
esp_err_t add(cluster_t *cluster, config_t *config)
{
if (!cluster || !config) {
ESP_LOGE(TAG, "Cluster or config cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
update_feature_map(cluster, get_id());
// Attributes not managed internally
attribute::create_ntp_server_available(cluster, config->ntp_server_available);
return ESP_OK;
}
} /* ntp_server */
namespace time_sync_client {
uint32_t get_id()
{
return static_cast<uint32_t>(TimeSynchronization::Feature::kTimeSyncClient);
}
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());
// Attributes managed internally
attribute::create_trusted_time_source(cluster, nullptr, 0, 0);
// Commands
command::create_set_trusted_time_source(cluster);
return ESP_OK;
}
} /* time_sync_client */
} /* feature */
} /* time_synchronization */
} /* cluster */
} /* esp_matter */
@@ -2395,5 +2395,46 @@ esp_err_t add(cluster_t *cluster);
} /* feature */
} /* pump_configuration_and_control */
namespace time_synchronization {
namespace feature {
namespace time_zone {
typedef struct config {
uint8_t time_zone_database;
config() : time_zone_database(2/* None */) {}
} config_t;
uint32_t get_id();
esp_err_t add(cluster_t *cluster, config_t *config);
} /* time_zone */
namespace ntp_client {
typedef struct config {
bool supports_dns_resolve;
config() : supports_dns_resolve(false) {}
} config_t;
uint32_t get_id();
esp_err_t add(cluster_t *cluster, config_t *config);
} /* ntp_client */
namespace ntp_server {
typedef struct config {
bool ntp_server_available;
config() : ntp_server_available(false) {}
} config_t;
uint32_t get_id();
esp_err_t add(cluster_t *cluster, config_t *config);
} /* ntp_server */
namespace time_sync_client {
uint32_t get_id();
esp_err_t add(cluster_t *cluster);
} /* time_sync_client */
} /* feature */
} /* time_synchronization */
} /* cluster */
} /* esp_matter */
+16
View File
@@ -24,6 +24,9 @@
#if CONFIG_DYNAMIC_PASSCODE_COMMISSIONABLE_DATA_PROVIDER
#include <custom_provider/dynamic_commissionable_data_provider.h>
#endif
#if CONFIG_ENABLE_SNTP_TIME_SYNC
#include <app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.h>
#endif
static const char *TAG = "app_main";
uint16_t switch_endpoint_id = 0;
@@ -109,6 +112,19 @@ extern "C" void app_main()
node::config_t node_config;
node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb);
ABORT_APP_ON_FAILURE(node != nullptr, ESP_LOGE(TAG, "Failed to create Matter node"));
#ifdef CONFIG_ENABLE_SNTP_TIME_SYNC
endpoint_t *root_node_ep = endpoint::get_first(node);
ABORT_APP_ON_FAILURE(root_node_ep != nullptr, ESP_LOGE(TAG, "Failed to find root node endpoint"));
cluster::time_synchronization::config_t time_sync_cfg;
static chip::app::Clusters::TimeSynchronization::DefaultTimeSyncDelegate time_sync_delegate;
time_sync_cfg.delegate = &time_sync_delegate;
cluster_t *time_sync_cluster = cluster::time_synchronization::create(root_node_ep, &time_sync_cfg, CLUSTER_FLAG_SERVER);
ABORT_APP_ON_FAILURE(time_sync_cluster != nullptr, ESP_LOGE(TAG, "Failed to create time_sync_cluster"));
cluster::time_synchronization::feature::time_zone::config_t tz_cfg;
cluster::time_synchronization::feature::time_zone::add(time_sync_cluster, &tz_cfg);
#endif
on_off_switch::config_t switch_config;
endpoint_t *endpoint = on_off_switch::create(node, &switch_config, ENDPOINT_FLAG_NONE, switch_handle);