diff --git a/examples/chef/common/chef-fan-control-manager.cpp b/examples/chef/common/chef-fan-control-manager.cpp index b30f58db27aee7..8d9ed5ae8bb699 100644 --- a/examples/chef/common/chef-fan-control-manager.cpp +++ b/examples/chef/common/chef-fan-control-manager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ using namespace chip; using namespace chip::app; +using namespace chip::app::DataModel; using namespace chip::app::Clusters; using namespace chip::app::Clusters::FanControl; using namespace chip::app::Clusters::FanControl::Attributes; @@ -43,38 +45,17 @@ class ChefFanControlManager : public AttributeAccessInterface, public Delegate AttributeAccessInterface(Optional(aEndpointId), FanControl::Id), Delegate(aEndpointId) {} + CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override; CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; Status HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; private: - CHIP_ERROR ReadPercentCurrent(AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSpeedCurrent(AttributeValueEncoder & aEncoder); + Nullable mPercentSetting{}; + Nullable mSpeedSetting{}; }; static std::unique_ptr mFanControlManager; -CHIP_ERROR ChefFanControlManager::ReadPercentCurrent(AttributeValueEncoder & aEncoder) -{ - // Return PercentSetting attribute value for now - DataModel::Nullable percentSetting; - Protocols::InteractionModel::Status status = PercentSetting::Get(mEndpoint, percentSetting); - - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, CHIP_ERROR_READ_FAILED); - - return aEncoder.Encode(percentSetting.ValueOr(0)); -} - -CHIP_ERROR ChefFanControlManager::ReadSpeedCurrent(AttributeValueEncoder & aEncoder) -{ - // Return SpeedCurrent attribute value for now - DataModel::Nullable speedSetting; - Protocols::InteractionModel::Status status = SpeedSetting::Get(mEndpoint, speedSetting); - - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, CHIP_ERROR_READ_FAILED); - - return aEncoder.Encode(speedSetting.ValueOr(0)); -} - Status ChefFanControlManager::HandleStep(StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) { ChipLogProgress(NotSpecified, "ChefFanControlManager::HandleStep aDirection %d, aWrap %d, aLowestOff %d", @@ -118,6 +99,73 @@ Status ChefFanControlManager::HandleStep(StepDirectionEnum aDirection, bool aWra return SpeedSetting::Set(mEndpoint, newSpeedSetting); } +CHIP_ERROR ChefFanControlManager::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) +{ + VerifyOrDie(aPath.mClusterId == FanControl::Id); + VerifyOrDie(aPath.mEndpointId == mEndpoint); + + switch (aPath.mAttributeId) + { + case SpeedSetting::Id: { + Nullable newSpeedSetting; + ReturnErrorOnFailure(aDecoder.Decode(newSpeedSetting)); + + // Ensure new speed is in bounds + { + uint8_t maxSpeedSetting = 0; + Protocols::InteractionModel::Status status = SpeedMax::Get(mEndpoint, &maxSpeedSetting); + VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_IM_GLOBAL_STATUS(Failure)); + + if (!newSpeedSetting.IsNull() && newSpeedSetting.Value() > maxSpeedSetting) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + } + + // Only act on changed. + if (newSpeedSetting != mSpeedSetting) + { + mSpeedSetting = newSpeedSetting; + + // Mark both the setting AND the current dirty, since the current always + // tracks the target for our product. + MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::SpeedSetting::Id); + MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::SpeedCurrent::Id); + } + + break; + } + case PercentSetting::Id: { + Nullable newPercentSetting; + ReturnErrorOnFailure(aDecoder.Decode(newPercentSetting)); + + // Ensure new speed in percent is valid. + if (!newPercentSetting.IsNull() && newPercentSetting.Value() > 100) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + // Only act on changed. + if (newPercentSetting != mPercentSetting) + { + mPercentSetting = newPercentSetting; + + // Mark both the setting AND the current dirty, since the current always + // tracks the target for our product. + MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::PercentSetting::Id); + MatterReportingAttributeChangeCallback(mEndpoint, FanControl::Id, Attributes::PercentCurrent::Id); + } + + break; + } + default: + break; + } + + // Fall through goes to attribute store legacy handling. + return CHIP_NO_ERROR; +} + CHIP_ERROR ChefFanControlManager::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { VerifyOrDie(aPath.mClusterId == FanControl::Id); @@ -125,10 +173,20 @@ CHIP_ERROR ChefFanControlManager::Read(const ConcreteReadAttributePath & aPath, switch (aPath.mAttributeId) { - case SpeedCurrent::Id: - return ReadSpeedCurrent(aEncoder); - case PercentCurrent::Id: - return ReadPercentCurrent(aEncoder); + case PercentCurrent::Id: { + // Current percents always tracks setting immediately in our implementation. + return aEncoder.Encode(mPercentSetting.ValueOr(0)); + } + case PercentSetting::Id: { + return aEncoder.Encode(mPercentSetting); + } + case SpeedCurrent::Id: { + // Current speed always tracks setting immediately in our implementation. + return aEncoder.Encode(mSpeedSetting.ValueOr(0)); + } + case SpeedSetting::Id: { + return aEncoder.Encode(mSpeedSetting); + } default: break; }