diff --git a/components/esp_matter/data_model/esp_matter_cluster.cpp b/components/esp_matter/data_model/esp_matter_cluster.cpp index 1061783dc..32681d834 100644 --- a/components/esp_matter/data_model/esp_matter_cluster.cpp +++ b/components/esp_matter/data_model/esp_matter_cluster.cpp @@ -4599,6 +4599,8 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags) /* Attributes not managed internally */ global::attribute::create_cluster_revision(cluster, cluster_revision); + cluster::set_init_and_shutdown_callbacks(cluster, ESPMatterSoilMeasurementClusterServerInitCallback, + ESPMatterSoilMeasurementClusterServerShutdownCallback); } if (flags & CLUSTER_FLAG_CLIENT) { diff --git a/components/esp_matter/data_model/esp_matter_endpoint.cpp b/components/esp_matter/data_model/esp_matter_endpoint.cpp index eddb89216..b710bd0ee 100644 --- a/components/esp_matter/data_model/esp_matter_endpoint.cpp +++ b/components/esp_matter/data_model/esp_matter_endpoint.cpp @@ -2274,6 +2274,33 @@ esp_err_t add(endpoint_t *endpoint, config_t *config) return ESP_OK; } } /* electrical_meter */ + +namespace soil_sensor { + +uint32_t get_device_type_id() +{ + return ESP_MATTER_SOIL_SENSOR_DEVICE_TYPE_ID; +} + +uint8_t get_device_type_version() +{ + return ESP_MATTER_SOIL_SENSOR_DEVICE_TYPE_VERSION; +} + +endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data) +{ + return common::create(node, config, flags, priv_data, add); +} + +esp_err_t add(endpoint_t *endpoint, config_t *config) +{ + esp_err_t err = add_device_type(endpoint, get_device_type_id(), get_device_type_version()); + VerifyOrReturnError(err == ESP_OK, err); + cluster::identify::create(endpoint, &(config->identify), CLUSTER_FLAG_SERVER); + cluster::soil_measurement::create(endpoint, &(config->soil_measurement), CLUSTER_FLAG_SERVER); + return ESP_OK; +} +} /* soil_sensor */ } /* endpoint */ namespace node { diff --git a/components/esp_matter/data_model/esp_matter_endpoint.h b/components/esp_matter/data_model/esp_matter_endpoint.h index 6af8e1a06..50f82e26c 100644 --- a/components/esp_matter/data_model/esp_matter_endpoint.h +++ b/components/esp_matter/data_model/esp_matter_endpoint.h @@ -167,6 +167,9 @@ #define ESP_MATTER_ELECTRICAL_ENERGY_TARIFF_DEVICE_TYPE_VERSION 1 #define ESP_MATTER_ELECTRICAL_METER_DEVICE_TYPE_ID 0x0514 #define ESP_MATTER_ELECTRICAL_METER_DEVICE_TYPE_VERSION 1 +#define ESP_MATTER_SOIL_SENSOR_DEVICE_TYPE_ID 0x0045 +#define ESP_MATTER_SOIL_SENSOR_DEVICE_TYPE_VERSION 1 + namespace esp_matter { /** Specific endpoint (device type) create APIs @@ -1149,6 +1152,19 @@ uint8_t get_device_type_version(); endpoint_t *create(node_t *node, config_t *config, uint8_t flags, void *priv_data); esp_err_t add(endpoint_t *endpoint, config_t *config); } /* electrical_meter */ + +namespace soil_sensor { +typedef struct config { + cluster::descriptor::config_t descriptor; + cluster::identify::config_t identify; + cluster::soil_measurement::config_t soil_measurement; +} 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); +esp_err_t add(endpoint_t *endpoint, config_t *config); +} /* soil_sensor */ } /* endpoint */ namespace node { diff --git a/components/esp_matter/data_model_provider/clusters/soil_measurement/integration.cpp b/components/esp_matter/data_model_provider/clusters/soil_measurement/integration.cpp new file mode 100644 index 000000000..c94369cb5 --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/soil_measurement/integration.cpp @@ -0,0 +1,79 @@ +// Copyright 2026 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "integration.h" +#include "esp_matter_data_model_provider.h" + +#include +#include +#include +#include +#include "support/CodeUtils.h" + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::SoilMeasurement; + +namespace { +std::unordered_map> gServers; +std::unordered_map gLimits; +} // namespace + +namespace chip::app::Clusters::SoilMeasurement { + +CHIP_ERROR SetSoilMoistureMeasuredValue( + EndpointId endpointId, + const SoilMeasurement::Attributes::SoilMoistureMeasuredValue::TypeInfo::Type &soilMoistureMeasuredValue) +{ + if (gServers[endpointId].IsConstructed()) { + return gServers[endpointId].Cluster().SetSoilMoistureMeasuredValue(soilMoistureMeasuredValue); + } + return CHIP_ERROR_INCORRECT_STATE; +} + +void SetSoilMoistureLimits( + EndpointId endpointId, + const SoilMeasurement::Attributes::SoilMoistureMeasurementLimits::TypeInfo::Type &soilMoistureLimits) +{ + gLimits[endpointId] = soilMoistureLimits; +} + +} // namespace chip::app::Clusters::SoilMeasurement + +void ESPMatterSoilMeasurementClusterServerInitCallback(EndpointId endpointId) +{ + if (gServers[endpointId].IsConstructed()) { + return; + } + VerifyOrDieWithMsg(gLimits.find(endpointId) != gLimits.end(), AppServer, + "Please set the limit for SoilMeasurementCluster on Endpoint 0x%" PRIx16, endpointId); + gServers[endpointId].Create(endpointId, gLimits[endpointId]); + + CHIP_ERROR err = + esp_matter::data_model::provider::get_instance().registry().Register(gServers[endpointId].Registration()); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "Failed to register SoilMeasurement - Error: %" CHIP_ERROR_FORMAT, err.Format()); + } +} + +void ESPMatterSoilMeasurementClusterServerShutdownCallback(EndpointId endpointId, ClusterShutdownType shutdownType) +{ + CHIP_ERROR err = + esp_matter::data_model::provider::get_instance().registry().Unregister(&gServers[endpointId].Cluster(), shutdownType); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "SoilMeasurement unregister error: %" CHIP_ERROR_FORMAT, err.Format()); + } + gServers[endpointId].Destroy(); +} diff --git a/components/esp_matter/data_model_provider/clusters/soil_measurement/integration.h b/components/esp_matter/data_model_provider/clusters/soil_measurement/integration.h new file mode 100644 index 000000000..bde34dc4e --- /dev/null +++ b/components/esp_matter/data_model_provider/clusters/soil_measurement/integration.h @@ -0,0 +1,30 @@ +// Copyright 2026 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +namespace chip::app::Clusters::SoilMeasurement { + +CHIP_ERROR SetSoilMoistureMeasuredValue( + EndpointId endpointId, + const SoilMeasurement::Attributes::SoilMoistureMeasuredValue::TypeInfo::Type &soilMoistureMeasuredValue); + +void SetSoilMoistureLimits( + EndpointId endpointId, + const SoilMeasurement::Attributes::SoilMoistureMeasurementLimits::TypeInfo::Type &soilMoistureLimits); + +} // namespace chip::app::Clusters::SoilMeasurement diff --git a/components/esp_matter/zap_common/app/ClusterCallbacks.cpp b/components/esp_matter/zap_common/app/ClusterCallbacks.cpp index 37207d6d5..38639ae3f 100644 --- a/components/esp_matter/zap_common/app/ClusterCallbacks.cpp +++ b/components/esp_matter/zap_common/app/ClusterCallbacks.cpp @@ -77,6 +77,16 @@ __attribute__((weak)) void ESPMatterAirQualityClusterServerShutdownCallback(Endp // Default empty implementation } +__attribute__((weak)) void ESPMatterAmbientContextSensingClusterServerInitCallback(EndpointId endpoint) +{ + // Default empty implementation +} + +__attribute__((weak)) void ESPMatterAmbientContextSensingClusterServerShutdownCallback(EndpointId endpoint) +{ + // Default empty implementation +} + __attribute__((weak)) void ESPMatterApplicationBasicClusterServerInitCallback(EndpointId endpoint) { // Default empty implementation diff --git a/examples/all_device_types_app/main/device_types.h b/examples/all_device_types_app/main/device_types.h index b955d8722..e2eef3233 100644 --- a/examples/all_device_types_app/main/device_types.h +++ b/examples/all_device_types_app/main/device_types.h @@ -67,6 +67,7 @@ enum device_type_enum { ESP_MATTER_ELECTRICAL_ENERGY_TARIFF, ESP_MATTER_ELECTRICAL_METER, ESP_MATTER_ELECTRICAL_UTILITY_METER, + ESP_MATTER_SOIL_SENSOR, ESP_MATTER_DEVICE_TYPE_MAX }; @@ -140,5 +141,6 @@ const device_type_name device_type_list[ESP_MATTER_DEVICE_TYPE_MAX] = { {"electrical_energy_tariff", ESP_MATTER_ELECTRICAL_ENERGY_TARIFF}, {"electrical_meter", ESP_MATTER_ELECTRICAL_METER}, {"electrical_utility_meter", ESP_MATTER_ELECTRICAL_UTILITY_METER}, + {"soil_sensor", ESP_MATTER_SOIL_SENSOR}, }; } /* namespace esp_matter */ diff --git a/examples/all_device_types_app/main/esp_matter_console_helpers.cpp b/examples/all_device_types_app/main/esp_matter_console_helpers.cpp index 40837fcdd..157971124 100644 --- a/examples/all_device_types_app/main/esp_matter_console_helpers.cpp +++ b/examples/all_device_types_app/main/esp_matter_console_helpers.cpp @@ -11,7 +11,12 @@ #include "esp_log.h" #include "esp_matter.h" #include "esp_console.h" +#include "esp_matter_data_model.h" #include "esp_vfs_dev.h" +#include "app/data-model/List.h" +#include "clusters/SoilMeasurement/Attributes.h" +#include "clusters/shared/Enums.h" +#include "clusters/shared/Structs.h" #include "linenoise/linenoise.h" #include "argtable3/argtable3.h" #include "esp_vfs_fat.h" @@ -28,6 +33,7 @@ #include #include #include +#include #include "electrical_measurement/electrical_measurement.h" #include "mock_delegates/mock_chime_delegate.h" @@ -641,6 +647,29 @@ int create(uint8_t device_type_index) endpoint = esp_matter::endpoint::electrical_utility_meter::create(node, &electrical_utility_meter_config, ENDPOINT_FLAG_NONE, NULL); break; } + case ESP_MATTER_SOIL_SENSOR: { + esp_matter::endpoint::soil_sensor::config_t soil_sensor_config; + endpoint = esp_matter::endpoint::soil_sensor::create(node, &soil_sensor_config, ENDPOINT_FLAG_NONE, NULL); + const Globals::Structs::MeasurementAccuracyRangeStruct::Type accuracyRange = { + .rangeMin = 0, + .rangeMax = 100, + .percentMax = MakeOptional(10), + .percentMin = NullOptional, + .percentTypical = NullOptional, + .fixedMax = NullOptional, + .fixedMin = NullOptional, + .fixedTypical = NullOptional, + }; + const Span accuracyRanges(&accuracyRange, 1); + chip::app::Clusters::SoilMeasurement::Attributes::SoilMoistureMeasurementLimits::TypeInfo::Type limits; + limits.measurementType = Globals::MeasurementTypeEnum::kSoilMoisture; + limits.measured = true, + limits.minMeasuredValue = 0; + limits.maxMeasuredValue = 100; + limits.accuracyRanges = app::DataModel::List(accuracyRanges); + chip::app::Clusters::SoilMeasurement::SetSoilMoistureLimits(esp_matter::endpoint::get_id(endpoint), limits); + break; + } default: { ESP_LOGE(TAG, "Please input a valid device type"); break;