esp_matter: add soil sensor device type

This commit is contained in:
WanqQixiang
2026-01-26 18:22:55 +08:00
parent 6456f3fbe2
commit 063f5c606d
8 changed files with 195 additions and 0 deletions
@@ -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) {
@@ -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<config_t>(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 {
@@ -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 {
@@ -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 <app/clusters/soil-measurement-server/SoilMeasurementCluster.h>
#include <app/server-cluster/ServerClusterInterfaceRegistry.h>
#include <clusters/SoilMeasurement/Attributes.h>
#include <unordered_map>
#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<EndpointId, LazyRegisteredServerCluster<SoilMeasurementCluster>> gServers;
std::unordered_map<EndpointId, Attributes::SoilMoistureMeasurementLimits::TypeInfo::Type> 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();
}
@@ -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 <app/clusters/soil-measurement-server/SoilMeasurementCluster.h>
#include <clusters/SoilMeasurement/Attributes.h>
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
@@ -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
@@ -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 */
@@ -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 <device_types.h>
#include <app/clusters/fan-control-server/fan-control-delegate.h>
#include <app/clusters/fan-control-server/fan-control-server.h>
#include <clusters/soil_measurement/integration.h>
#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<chip::Percent100ths>(10),
.percentMin = NullOptional,
.percentTypical = NullOptional,
.fixedMax = NullOptional,
.fixedMin = NullOptional,
.fixedTypical = NullOptional,
};
const Span<const Globals::Structs::MeasurementAccuracyRangeStruct::Type> 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<const Globals::Structs::MeasurementAccuracyRangeStruct::Type>(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;