From 7bc498b54127a343ae9304f7897ff6ce2f839898 Mon Sep 17 00:00:00 2001 From: Erwin Pan Date: Mon, 17 Jun 2024 20:10:13 +0800 Subject: [PATCH] [Chef] Fix Read/Write Attributes of AirPurifier's clusters. (#33848) * Fix TLV Reader in LastChangedTime * Restyled by whitespace * Restyled by clang-format * Fix debug messages * Using BufferReader / BufferWriter to avoid Endianness Using BufferReader / BufferWriter to avoid Endianness issue * Restyled by clang-format * Fix DegradationDirection Get --------- Co-authored-by: Restyled.io --- .../chef-resource-monitoring-delegates.cpp | 157 --------- .../chef-resource-monitoring-delegates.cpp | 311 ++++++++++++++++++ .../chef-resource-monitoring-delegates.h | 53 ++- examples/chef/common/stubs.cpp | 13 + .../rootnode_airpurifier_73a6fe2651.matter | 88 +++++ .../rootnode_airpurifier_73a6fe2651.zap | 163 ++++++++- examples/chef/esp32/main/CMakeLists.txt | 1 + examples/chef/linux/BUILD.gn | 2 +- examples/chef/nrfconnect/CMakeLists.txt | 2 +- 9 files changed, 617 insertions(+), 173 deletions(-) delete mode 100644 examples/chef/common/chef-resource-monitoring-delegates.cpp create mode 100644 examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.cpp rename examples/chef/common/{ => clusters/resource-monitoring}/chef-resource-monitoring-delegates.h (54%) diff --git a/examples/chef/common/chef-resource-monitoring-delegates.cpp b/examples/chef/common/chef-resource-monitoring-delegates.cpp deleted file mode 100644 index ca2b713385669d..00000000000000 --- a/examples/chef/common/chef-resource-monitoring-delegates.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * - * 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 -#include -#include -#include -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::ResourceMonitoring; -using namespace chip::app::Clusters::ActivatedCarbonFilterMonitoring; -using namespace chip::app::Clusters::HepaFilterMonitoring; -using chip::Protocols::InteractionModel::Status; - -const chip::BitMask gHepaFilterFeatureMap(ResourceMonitoring::Feature::kCondition, - ResourceMonitoring::Feature::kWarning, - ResourceMonitoring::Feature::kReplacementProductList); -const chip::BitMask gActivatedCarbonFeatureMap(ResourceMonitoring::Feature::kCondition, - ResourceMonitoring::Feature::kWarning, - ResourceMonitoring::Feature::kReplacementProductList); - -static std::unique_ptr gActivatedCarbonFilterDelegate; -static std::unique_ptr gActivatedCarbonFilterInstance; - -static std::unique_ptr gHepaFilterDelegate; -static std::unique_ptr gHepaFilterInstance; - -static ImmutableReplacementProductListManager sReplacementProductListManager; - -//-- Activated Carbon Filter Monitoring delegate methods -CHIP_ERROR ActivatedCarbonFilterMonitoringDelegate::Init() -{ - ChipLogDetail(Zcl, "ActivatedCarbonFilterMonitoringDelegate::Init()"); - GetInstance()->SetReplacementProductListManagerInstance(&sReplacementProductListManager); - return CHIP_NO_ERROR; -} - -Status ActivatedCarbonFilterMonitoringDelegate::PreResetCondition() -{ - ChipLogDetail(Zcl, "ActivatedCarbonFilterMonitoringDelegate::PreResetCondition()"); - return Status::Success; -} - -Status ActivatedCarbonFilterMonitoringDelegate::PostResetCondition() -{ - ChipLogDetail(Zcl, "ActivatedCarbonFilterMonitoringDelegate::PostResetCondition()"); - return Status::Success; -} - -void ActivatedCarbonFilterMonitoring::Shutdown() -{ - gActivatedCarbonFilterInstance.reset(); - gActivatedCarbonFilterDelegate.reset(); -} - -//-- Hepa Filter Monitoring delegate methods -CHIP_ERROR HepaFilterMonitoringDelegate::Init() -{ - ChipLogDetail(Zcl, "HepaFilterMonitoringDelegate::Init()"); - GetInstance()->SetReplacementProductListManagerInstance(&sReplacementProductListManager); - return CHIP_NO_ERROR; -} - -Status HepaFilterMonitoringDelegate::PreResetCondition() -{ - ChipLogDetail(Zcl, "HepaFilterMonitoringDelegate::PreResetCondition()"); - return Status::Success; -} - -Status HepaFilterMonitoringDelegate::PostResetCondition() -{ - ChipLogDetail(Zcl, "HepaFilterMonitoringDelegate::PostResetCondition()"); - return Status::Success; -} - -void HepaFilterMonitoring::Shutdown() -{ - gHepaFilterInstance.reset(); - gHepaFilterDelegate.reset(); -} - -void emberAfActivatedCarbonFilterMonitoringClusterInitCallback(chip::EndpointId endpoint) -{ - VerifyOrDie(!gActivatedCarbonFilterInstance && !gActivatedCarbonFilterDelegate); - gActivatedCarbonFilterDelegate = std::make_unique(); - bool bResetConditionCommandSupported = true; // The ResetCondition command is supported by the ResourceMonitor cluster - gActivatedCarbonFilterInstance = std::make_unique( - gActivatedCarbonFilterDelegate.get(), endpoint, ActivatedCarbonFilterMonitoring::Id, - static_cast(gActivatedCarbonFeatureMap.Raw()), ResourceMonitoring::DegradationDirectionEnum::kDown, - bResetConditionCommandSupported); - gActivatedCarbonFilterInstance->Init(); -} - -void emberAfHepaFilterMonitoringClusterInitCallback(chip::EndpointId endpoint) -{ - VerifyOrDie(!gHepaFilterInstance && !gHepaFilterDelegate); - - gHepaFilterDelegate = std::make_unique(); - bool bResetConditionCommandSupported = true; // The ResetCondition command is supported by the ResourceMonitor cluster - gHepaFilterInstance = std::make_unique( - gHepaFilterDelegate.get(), endpoint, HepaFilterMonitoring::Id, static_cast(gHepaFilterFeatureMap.Raw()), - ResourceMonitoring::DegradationDirectionEnum::kDown, bResetConditionCommandSupported); - gHepaFilterInstance->Init(); -} - -CHIP_ERROR ImmutableReplacementProductListManager::Next(ReplacementProductStruct & item) -{ - if (mIndex >= kReplacementProductListMaxSize) - { - return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; - } - - switch (mIndex) - { - case 0: - item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kUpc); - item.SetProductIdentifierValue(CharSpan::fromCharString("111112222233")); - break; - case 1: - item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kGtin8); - item.SetProductIdentifierValue(CharSpan::fromCharString("gtin8xxx")); - break; - case 2: - item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kEan); - item.SetProductIdentifierValue(CharSpan::fromCharString("4444455555666")); - break; - case 3: - item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kGtin14); - item.SetProductIdentifierValue(CharSpan::fromCharString("gtin14xxxxxxxx")); - break; - case 4: - item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kOem); - item.SetProductIdentifierValue(CharSpan::fromCharString("oem20xxxxxxxxxxxxxxx")); - break; - default: - return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; - } - mIndex++; - return CHIP_NO_ERROR; -} diff --git a/examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.cpp b/examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.cpp new file mode 100644 index 00000000000000..9b0f6d8df13404 --- /dev/null +++ b/examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.cpp @@ -0,0 +1,311 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::ResourceMonitoring; +using namespace chip::app::Clusters::ActivatedCarbonFilterMonitoring; +using namespace chip::app::Clusters::HepaFilterMonitoring; +using chip::Protocols::InteractionModel::Status; + +const chip::BitMask gHepaFilterFeatureMap(ResourceMonitoring::Feature::kCondition, + ResourceMonitoring::Feature::kWarning, + ResourceMonitoring::Feature::kReplacementProductList); +const chip::BitMask gActivatedCarbonFeatureMap(ResourceMonitoring::Feature::kCondition, + ResourceMonitoring::Feature::kWarning, + ResourceMonitoring::Feature::kReplacementProductList); + +static std::unique_ptr gActivatedCarbonFilterDelegate; +static std::unique_ptr gActivatedCarbonFilterInstance; + +static std::unique_ptr gHepaFilterDelegate; +static std::unique_ptr gHepaFilterInstance; + +static ImmutableReplacementProductListManager sReplacementProductListManager; + +//-- Activated Carbon Filter Monitoring delegate methods +CHIP_ERROR ActivatedCarbonFilterMonitoringDelegate::Init() +{ + ChipLogDetail(Zcl, "ActivatedCarbonFilterMonitoringDelegate::Init()"); + GetInstance()->SetReplacementProductListManagerInstance(&sReplacementProductListManager); + return CHIP_NO_ERROR; +} + +Status ActivatedCarbonFilterMonitoringDelegate::PreResetCondition() +{ + ChipLogDetail(Zcl, "ActivatedCarbonFilterMonitoringDelegate::PreResetCondition()"); + return Status::Success; +} + +Status ActivatedCarbonFilterMonitoringDelegate::PostResetCondition() +{ + ChipLogDetail(Zcl, "ActivatedCarbonFilterMonitoringDelegate::PostResetCondition()"); + return Status::Success; +} + +void ActivatedCarbonFilterMonitoring::Shutdown() +{ + gActivatedCarbonFilterInstance.reset(); + gActivatedCarbonFilterDelegate.reset(); +} + +//-- Hepa Filter Monitoring delegate methods +CHIP_ERROR HepaFilterMonitoringDelegate::Init() +{ + ChipLogDetail(Zcl, "HepaFilterMonitoringDelegate::Init()"); + GetInstance()->SetReplacementProductListManagerInstance(&sReplacementProductListManager); + return CHIP_NO_ERROR; +} + +Status HepaFilterMonitoringDelegate::PreResetCondition() +{ + ChipLogDetail(Zcl, "HepaFilterMonitoringDelegate::PreResetCondition()"); + return Status::Success; +} + +Status HepaFilterMonitoringDelegate::PostResetCondition() +{ + ChipLogDetail(Zcl, "HepaFilterMonitoringDelegate::PostResetCondition()"); + return Status::Success; +} + +void HepaFilterMonitoring::Shutdown() +{ + gHepaFilterInstance.reset(); + gHepaFilterDelegate.reset(); +} + +chip::Protocols::InteractionModel::Status +ChefResourceMonitorInstance::ExternalAttributeWrite(const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer) +{ + Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Success; + AttributeId attributeId = attributeMetadata->attributeId; + + switch (attributeId) + { + case HepaFilterMonitoring::Attributes::Condition::Id: { + uint8_t newCondition = *(uint8_t *) buffer; + ret = UpdateCondition(newCondition); + } + break; + case HepaFilterMonitoring::Attributes::ChangeIndication::Id: { + ResourceMonitoring::ChangeIndicationEnum newIndication = + static_cast(*(uint8_t *) buffer); + ret = UpdateChangeIndication(newIndication); + } + break; + case HepaFilterMonitoring::Attributes::InPlaceIndicator::Id: { + bool newInPlaceIndicator = *(bool *) buffer; + ret = UpdateInPlaceIndicator(newInPlaceIndicator); + } + break; + case HepaFilterMonitoring::Attributes::LastChangedTime::Id: { + // We already know the input is a buffer started with a uint16_t as the length + chip::Encoding::LittleEndian::Reader bufReader(buffer, sizeof(uint16_t)); + uint16_t tlvLen; + VerifyOrReturnError(CHIP_NO_ERROR == bufReader.Read16(&tlvLen).StatusCode(), + Protocols::InteractionModel::Status::UnsupportedWrite); + + // Read from TLV + uint32_t newValue = 0; + chip::TLV::TLVReader tlvReader; + tlvReader.Init(buffer + sizeof(uint16_t), tlvLen); + tlvReader.Next(); + tlvReader.Get(newValue); + DataModel::Nullable newLastChangedTime = DataModel::MakeNullable(newValue); + ret = UpdateLastChangedTime(newLastChangedTime); + } + break; + case HepaFilterMonitoring::Attributes::DegradationDirection::Id: + default: { + ChipLogError(Zcl, "Unsupported External Attribute Write: %d", static_cast(attributeId)); + ret = Protocols::InteractionModel::Status::UnsupportedWrite; + } + break; + } + + return ret; +} + +void emberAfActivatedCarbonFilterMonitoringClusterInitCallback(chip::EndpointId endpoint) +{ + VerifyOrDie(!gActivatedCarbonFilterInstance && !gActivatedCarbonFilterDelegate); + + bool bResetConditionCommandSupported = true; // The ResetCondition command is supported by the ResourceMonitor cluster + gActivatedCarbonFilterDelegate = std::make_unique(); + gActivatedCarbonFilterInstance = std::make_unique( + gActivatedCarbonFilterDelegate.get(), endpoint, ActivatedCarbonFilterMonitoring::Id, + static_cast(gActivatedCarbonFeatureMap.Raw()), ResourceMonitoring::DegradationDirectionEnum::kDown, + bResetConditionCommandSupported); + gActivatedCarbonFilterInstance->Init(); +} + +chip::Protocols::InteractionModel::Status +chefResourceMonitoringExternalWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer) +{ + Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Success; + AttributeId attributeId = attributeMetadata->attributeId; + ChipLogProgress(Zcl, "chefResourceMonitoringExternalWriteCallback EP: %d, Cluster: %04x, Att: %04x", static_cast(endpoint), + static_cast(clusterId), static_cast(attributeId)); + + switch (clusterId) + { + case HepaFilterMonitoring::Id: + ret = gHepaFilterInstance->ExternalAttributeWrite(attributeMetadata, buffer); + break; + case ActivatedCarbonFilterMonitoring::Id: + ret = gActivatedCarbonFilterInstance->ExternalAttributeWrite(attributeMetadata, buffer); + break; + default: + ret = Protocols::InteractionModel::Status::UnsupportedWrite; + break; + } + + return ret; +} + +chip::Protocols::InteractionModel::Status +chefResourceMonitoringExternalReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, + uint16_t maxReadLength) +{ + Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Success; + AttributeId attributeId = attributeMetadata->attributeId; + ChipLogProgress(Zcl, "chefResourceMonitoringExternalReadCallback EP: %d, Cluster: %d, Att: %d", static_cast(endpoint), + static_cast(clusterId), static_cast(attributeId)); + + switch (clusterId) + { + case HepaFilterMonitoring::Id: + ret = gHepaFilterInstance->ExternalAttributeRead(attributeMetadata, buffer, maxReadLength); + break; + case ActivatedCarbonFilterMonitoring::Id: + ret = gActivatedCarbonFilterInstance->ExternalAttributeRead(attributeMetadata, buffer, maxReadLength); + break; + default: + ret = Protocols::InteractionModel::Status::UnsupportedRead; + break; + } + + return ret; +} + +chip::Protocols::InteractionModel::Status +ChefResourceMonitorInstance::ExternalAttributeRead(const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, + uint16_t maxReadLength) +{ + Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Success; + AttributeId attributeId = attributeMetadata->attributeId; + + switch (attributeId) + { + case HepaFilterMonitoring::Attributes::Condition::Id: { + *buffer = GetCondition(); + } + break; + case HepaFilterMonitoring::Attributes::ChangeIndication::Id: { + ResourceMonitoring::ChangeIndicationEnum changeIndication = GetChangeIndication(); + // The underlying type of ResourceMonitoring::ChangeIndicationEnum is uint8_t + *buffer = to_underlying(changeIndication); + } + break; + case HepaFilterMonitoring::Attributes::InPlaceIndicator::Id: { + *(bool *) buffer = GetInPlaceIndicator(); + } + break; + case HepaFilterMonitoring::Attributes::LastChangedTime::Id: { + // Only LastChangedTime needs to handle Endianness + DataModel::Nullable lastChangedTime = GetLastChangedTime(); + chip::Encoding::LittleEndian::BufferWriter bufWriter(buffer, sizeof(uint16_t)); + + bufWriter.Put32(lastChangedTime.IsNull() ? 0 : lastChangedTime.Value()); + } + break; + case HepaFilterMonitoring::Attributes::DegradationDirection::Id: { + ResourceMonitoring::DegradationDirectionEnum degradationDirection = GetDegradationDirection(); + // The underlying type of ResourceMonitoring::DegradationDirectionEnum is uint8_t + *buffer = to_underlying(degradationDirection); + } + break; + default: + ChipLogError(Zcl, "Unsupported External Attribute Read: %d", static_cast(attributeId)); + ret = Protocols::InteractionModel::Status::UnsupportedRead; + break; + } + + return ret; +} + +void emberAfHepaFilterMonitoringClusterInitCallback(chip::EndpointId endpoint) +{ + VerifyOrDie(!gHepaFilterInstance && !gHepaFilterDelegate); + + bool bResetConditionCommandSupported = true; // The ResetCondition command is supported by the ResourceMonitor cluster + gHepaFilterDelegate = std::make_unique(); + gHepaFilterInstance = std::make_unique( + gHepaFilterDelegate.get(), endpoint, HepaFilterMonitoring::Id, static_cast(gHepaFilterFeatureMap.Raw()), + ResourceMonitoring::DegradationDirectionEnum::kDown, bResetConditionCommandSupported); + gHepaFilterInstance->Init(); +} + +CHIP_ERROR ImmutableReplacementProductListManager::Next(ReplacementProductStruct & item) +{ + if (mIndex >= kReplacementProductListMaxSize) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + + switch (mIndex) + { + case 0: + item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kUpc); + item.SetProductIdentifierValue(CharSpan::fromCharString("111112222233")); + break; + case 1: + item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kGtin8); + item.SetProductIdentifierValue(CharSpan::fromCharString("gtin8xxx")); + break; + case 2: + item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kEan); + item.SetProductIdentifierValue(CharSpan::fromCharString("4444455555666")); + break; + case 3: + item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kGtin14); + item.SetProductIdentifierValue(CharSpan::fromCharString("gtin14xxxxxxxx")); + break; + case 4: + item.SetProductIdentifierType(ResourceMonitoring::ProductIdentifierTypeEnum::kOem); + item.SetProductIdentifierValue(CharSpan::fromCharString("oem20xxxxxxxxxxxxxxx")); + break; + default: + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + mIndex++; + return CHIP_NO_ERROR; +} diff --git a/examples/chef/common/chef-resource-monitoring-delegates.h b/examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.h similarity index 54% rename from examples/chef/common/chef-resource-monitoring-delegates.h rename to examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.h index f161be0006a238..2334be90b4ab3a 100644 --- a/examples/chef/common/chef-resource-monitoring-delegates.h +++ b/examples/chef/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,21 +24,25 @@ namespace chip { namespace app { namespace Clusters { -namespace ActivatedCarbonFilterMonitoring { -class ActivatedCarbonFilterMonitoringDelegate : public ResourceMonitoring::Delegate -{ -private: - CHIP_ERROR Init() override; - chip::Protocols::InteractionModel::Status PreResetCondition() override; - chip::Protocols::InteractionModel::Status PostResetCondition() override; +namespace ResourceMonitoring { +// Inherit ResourceMonitoring class to able to write external attributes +class ChefResourceMonitorInstance : public ResourceMonitoring::Instance +{ public: - ~ActivatedCarbonFilterMonitoringDelegate() override = default; -}; + ChefResourceMonitorInstance(Delegate * aDelegate, EndpointId aEndpointId, ClusterId aClusterId, uint32_t aFeatureMap, + ResourceMonitoring::Attributes::DegradationDirection::TypeInfo::Type aDegradationDirection, + bool aResetConditionCommandSupported) : + ResourceMonitoring::Instance(aDelegate, aEndpointId, aClusterId, aFeatureMap, aDegradationDirection, + aResetConditionCommandSupported){}; -void Shutdown(); + chip::Protocols::InteractionModel::Status ExternalAttributeWrite(const EmberAfAttributeMetadata * attributeMetadata, + uint8_t * buffer); + chip::Protocols::InteractionModel::Status ExternalAttributeRead(const EmberAfAttributeMetadata * attributeMetadata, + uint8_t * buffer, uint16_t maxReadLength); +}; -} // namespace ActivatedCarbonFilterMonitoring +} // namespace ResourceMonitoring namespace HepaFilterMonitoring { class HepaFilterMonitoringDelegate : public ResourceMonitoring::Delegate @@ -63,6 +67,31 @@ void Shutdown(); } // namespace HepaFilterMonitoring +namespace ActivatedCarbonFilterMonitoring { +class ActivatedCarbonFilterMonitoringDelegate : public ResourceMonitoring::Delegate +{ +private: + CHIP_ERROR Init() override; + chip::Protocols::InteractionModel::Status PreResetCondition() override; + chip::Protocols::InteractionModel::Status PostResetCondition() override; + +public: + ~ActivatedCarbonFilterMonitoringDelegate() override = default; +}; + +void Shutdown(); + +} // namespace ActivatedCarbonFilterMonitoring + } // namespace Clusters } // namespace app } // namespace chip + +chip::Protocols::InteractionModel::Status +chefResourceMonitoringExternalWriteCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer); + +chip::Protocols::InteractionModel::Status +chefResourceMonitoringExternalReadCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, + const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, + uint16_t maxReadLength); diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp index c0935df51efa7e..8771bf78dccaf5 100644 --- a/examples/chef/common/stubs.cpp +++ b/examples/chef/common/stubs.cpp @@ -18,6 +18,9 @@ defined(MATTER_DM_PLUGIN_RADON_CONCENTRATION_MEASUREMENT_SERVER) #include "chef-concentration-measurement.h" #endif +#if defined(MATTER_DM_PLUGIN_HEPA_FILTER_MONITORING_SERVER) || defined(MATTER_DM_PLUGIN_ACTIVATED_CARBON_FILTER_MONITORING_SERVER) +#include "resource-monitoring/chef-resource-monitoring-delegates.h" +#endif #if defined(MATTER_DM_PLUGIN_RVC_RUN_MODE_SERVER) || defined(MATTER_DM_PLUGIN_RVC_CLEAN_MODE_SERVER) #include "chef-rvc-mode-delegate.h" @@ -65,6 +68,11 @@ Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(Endpoin case chip::app::Clusters::TotalVolatileOrganicCompoundsConcentrationMeasurement::Id: return chefConcentrationMeasurementReadCallback(endpoint, clusterId, attributeMetadata, buffer, maxReadLength); #endif +#if defined(MATTER_DM_PLUGIN_HEPA_FILTER_MONITORING_SERVER) || defined(MATTER_DM_PLUGIN_ACTIVATED_CARBON_FILTER_MONITORING_SERVER) + case chip::app::Clusters::HepaFilterMonitoring::Id: + case chip::app::Clusters::ActivatedCarbonFilterMonitoring::Id: + return chefResourceMonitoringExternalReadCallback(endpoint, clusterId, attributeMetadata, buffer, maxReadLength); +#endif #ifdef MATTER_DM_PLUGIN_RVC_RUN_MODE_SERVER case chip::app::Clusters::RvcRunMode::Id: return chefRvcRunModeReadCallback(endpoint, clusterId, attributeMetadata, buffer, maxReadLength); @@ -125,6 +133,11 @@ Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(Endpoi case chip::app::Clusters::TotalVolatileOrganicCompoundsConcentrationMeasurement::Id: return chefConcentrationMeasurementWriteCallback(endpoint, clusterId, attributeMetadata, buffer); #endif +#if defined(MATTER_DM_PLUGIN_HEPA_FILTER_MONITORING_SERVER) || defined(MATTER_DM_PLUGIN_ACTIVATED_CARBON_FILTER_MONITORING_SERVER) + case chip::app::Clusters::HepaFilterMonitoring::Id: + case chip::app::Clusters::ActivatedCarbonFilterMonitoring::Id: + return chefResourceMonitoringExternalWriteCallback(endpoint, clusterId, attributeMetadata, buffer); +#endif #ifdef MATTER_DM_PLUGIN_RVC_RUN_MODE_SERVER case chip::app::Clusters::RvcRunMode::Id: return chefRvcRunModeWriteCallback(endpoint, clusterId, attributeMetadata, buffer); diff --git a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter index 2ec8dae0409d96..21d3d20264049e 100644 --- a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter +++ b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter @@ -51,6 +51,78 @@ cluster Identify = 3 { command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; } +/** Attributes and commands for switching devices between 'On' and 'Off' states. */ +cluster OnOff = 6 { + revision 6; + + enum DelayedAllOffEffectVariantEnum : enum8 { + kDelayedOffFastFade = 0; + kNoFade = 1; + kDelayedOffSlowFade = 2; + } + + enum DyingLightEffectVariantEnum : enum8 { + kDyingLightFadeOff = 0; + } + + enum EffectIdentifierEnum : enum8 { + kDelayedAllOff = 0; + kDyingLight = 1; + } + + enum StartUpOnOffEnum : enum8 { + kOff = 0; + kOn = 1; + kToggle = 2; + } + + bitmap Feature : bitmap32 { + kLighting = 0x1; + kDeadFrontBehavior = 0x2; + kOffOnly = 0x4; + } + + bitmap OnOffControlBitmap : bitmap8 { + kAcceptOnlyWhenOn = 0x1; + } + + readonly attribute boolean onOff = 0; + readonly attribute optional boolean globalSceneControl = 16384; + attribute optional int16u onTime = 16385; + attribute optional int16u offWaitTime = 16386; + attribute access(write: manage) optional nullable StartUpOnOffEnum startUpOnOff = 16387; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct OffWithEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + enum8 effectVariant = 1; + } + + request struct OnWithTimedOffRequest { + OnOffControlBitmap onOffControl = 0; + int16u onTime = 1; + int16u offWaitTime = 2; + } + + /** On receipt of this command, a device SHALL enter its ‘Off’ state. This state is device dependent, but it is recommended that it is used for power off or similar functions. On receipt of the Off command, the OnTime attribute SHALL be set to 0. */ + command Off(): DefaultSuccess = 0; + /** On receipt of this command, a device SHALL enter its ‘On’ state. This state is device dependent, but it is recommended that it is used for power on or similar functions. On receipt of the On command, if the value of the OnTime attribute is equal to 0, the device SHALL set the OffWaitTime attribute to 0. */ + command On(): DefaultSuccess = 1; + /** On receipt of this command, if a device is in its ‘Off’ state it SHALL enter its ‘On’ state. Otherwise, if it is in its ‘On’ state it SHALL enter its ‘Off’ state. On receipt of the Toggle command, if the value of the OnOff attribute is equal to FALSE and if the value of the OnTime attribute is equal to 0, the device SHALL set the OffWaitTime attribute to 0. If the value of the OnOff attribute is equal to TRUE, the OnTime attribute SHALL be set to 0. */ + command Toggle(): DefaultSuccess = 2; + /** The OffWithEffect command allows devices to be turned off using enhanced ways of fading. */ + command OffWithEffect(OffWithEffectRequest): DefaultSuccess = 64; + /** The OnWithRecallGlobalScene command allows the recall of the settings when the device was turned off. */ + command OnWithRecallGlobalScene(): DefaultSuccess = 65; + /** The OnWithTimedOff command allows devices to be turned on for a specific duration with a guarded off duration so that SHOULD the device be subsequently switched off, further OnWithTimedOff commands, received during this time, are prevented from turning the devices back on. */ + command OnWithTimedOff(OnWithTimedOffRequest): DefaultSuccess = 66; +} + /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ cluster Descriptor = 29 { revision 2; @@ -1552,6 +1624,20 @@ endpoint 1 { handle command Identify; } + server cluster OnOff { + ram attribute onOff default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 6; + + handle command Off; + handle command On; + handle command Toggle; + } + server cluster Descriptor { callback attribute deviceTypeList; callback attribute serverList; @@ -1578,6 +1664,8 @@ endpoint 1 { callback attribute attributeList; callback attribute featureMap; ram attribute clusterRevision default = 1; + + handle command ResetCondition; } server cluster ActivatedCarbonFilterMonitoring { diff --git a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.zap b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.zap index 4e5b3241032f45..fc392ea914fffe 100644 --- a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.zap +++ b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.zap @@ -1,6 +1,6 @@ { "fileFormat": 2, - "featureLevel": 100, + "featureLevel": 102, "creator": "zap", "keyValuePairs": [ { @@ -29,6 +29,7 @@ "pathRelativity": "relativeToZap", "path": "../../../src/app/zap-templates/app-templates.json", "type": "gen-templates-json", + "category": "matter", "version": "chip-v1" } ], @@ -2468,6 +2469,154 @@ } ] }, + { + "name": "On/Off", + "code": 6, + "mfgCode": null, + "define": "ON_OFF_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Off", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "On", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "Toggle", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "OnOff", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Descriptor", "code": 29, @@ -2645,6 +2794,16 @@ "define": "HEPA_FILTER_MONITORING_CLUSTER", "side": "server", "enabled": 1, + "commands": [ + { + "name": "ResetCondition", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], "attributes": [ { "name": "Condition", @@ -2836,7 +2995,7 @@ "reportable": 1, "minInterval": 1, "maxInterval": 65534, - "reportableChange": 0 + "reportableChange": 1 } ] }, diff --git a/examples/chef/esp32/main/CMakeLists.txt b/examples/chef/esp32/main/CMakeLists.txt index c6b37a0675fa4c..1614669713e5a0 100644 --- a/examples/chef/esp32/main/CMakeLists.txt +++ b/examples/chef/esp32/main/CMakeLists.txt @@ -70,6 +70,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/../common/clusters/low-power/" "${CMAKE_SOURCE_DIR}/../common/clusters/media-input/" "${CMAKE_SOURCE_DIR}/../common/clusters/media-playback/" + "${CMAKE_SOURCE_DIR}/../common/clusters/resource-monitoring/" "${CMAKE_SOURCE_DIR}/../common/clusters/switch/" "${CMAKE_SOURCE_DIR}/../common/clusters/target-navigator/" "${CMAKE_SOURCE_DIR}/../common/clusters/wake-on-lan/" diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index ce0bed596850ef..c9c0be1d74156b 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -46,7 +46,6 @@ executable("${sample_name}") { "${project_dir}/common/chef-laundry-washer-controls-delegate-impl.cpp", "${project_dir}/common/chef-laundry-washer-mode.cpp", "${project_dir}/common/chef-operational-state-delegate-impl.cpp", - "${project_dir}/common/chef-resource-monitoring-delegates.cpp", "${project_dir}/common/chef-rpc-actions-worker.cpp", "${project_dir}/common/chef-rvc-mode-delegate.cpp", "${project_dir}/common/chef-rvc-operational-state-delegate.cpp", @@ -59,6 +58,7 @@ executable("${sample_name}") { "${project_dir}/common/clusters/low-power/LowPowerManager.cpp", "${project_dir}/common/clusters/media-input/MediaInputManager.cpp", "${project_dir}/common/clusters/media-playback/MediaPlaybackManager.cpp", + "${project_dir}/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.cpp", "${project_dir}/common/clusters/switch/SwitchEventHandler.cpp", "${project_dir}/common/clusters/switch/SwitchManager.cpp", "${project_dir}/common/clusters/target-navigator/TargetNavigatorManager.cpp", diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt index a22f6b6972bb15..98f5cdeafdca75 100644 --- a/examples/chef/nrfconnect/CMakeLists.txt +++ b/examples/chef/nrfconnect/CMakeLists.txt @@ -87,7 +87,6 @@ target_sources(app PRIVATE ${CHEF}/common/chef-laundry-washer-controls-delegate-impl.cpp ${CHEF}/common/chef-laundry-washer-mode.cpp ${CHEF}/common/chef-operational-state-delegate-impl.cpp - ${CHEF}/common/chef-resource-monitoring-delegates.cpp ${CHEF}/common/chef-rvc-mode-delegate.cpp ${CHEF}/common/chef-rvc-operational-state-delegate.cpp ${CHEF}/common/clusters/audio-output/AudioOutputManager.cpp @@ -99,6 +98,7 @@ target_sources(app PRIVATE ${CHEF}/common/clusters/low-power/LowPowerManager.cpp ${CHEF}/common/clusters/media-input/MediaInputManager.cpp ${CHEF}/common/clusters/media-playback/MediaPlaybackManager.cpp + ${CHEF}/common/clusters/resource-monitoring/chef-resource-monitoring-delegates.cpp ${CHEF}/common/clusters/switch/SwitchEventHandler.cpp ${CHEF}/common/clusters/switch/SwitchManager.cpp ${CHEF}/common/clusters/target-navigator/TargetNavigatorManager.cpp