blob: c58e5c5a73743a0abf65b016687784edf7692975 [file] [log] [blame]
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* 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-common/zap-generated/cluster-objects.h>
#include <app/AttributeAccessInterface.h>
#include <app/CommandHandlerInterface.h>
#include <app/ConcreteAttributePath.h>
#include <app/InteractionModelEngine.h>
#include <app/MessageDef/StatusIB.h>
#include <app/reporting/reporting.h>
#include <app/util/attribute-storage.h>
#include <lib/core/CHIPError.h>
#include <protocols/interaction_model/StatusCode.h>
namespace chip {
namespace app {
namespace Clusters {
namespace DeviceEnergyManagement {
class Delegate
{
public:
virtual ~Delegate() = default;
void SetEndpointId(EndpointId aEndpoint) { mEndpointId = aEndpoint; }
/**
* @brief Delegate should implement a handler to begin to adjust client power
* consumption/generation to the level requested.
*
* Note callers must call GetPowerAdjustmentCapability and ensure the return value is not null
* before calling PowerAdjustRequest.
*
* @param power Milli-Watts the ESA SHALL use during the adjustment period.
* @param duration The duration that the ESA SHALL maintain the requested power for.
* @return Success if the adjustment is accepted; otherwise the command SHALL be rejected with appropriate error.
*/
virtual Protocols::InteractionModel::Status PowerAdjustRequest(const int64_t power, const uint32_t duration,
AdjustmentCauseEnum cause) = 0;
/**
* @brief Delegate SHALL make the ESA end the active power adjustment session & return to normal (or idle) power levels.
* The ESA SHALL also generate an PowerAdjustEnd Event and the ESAState SHALL be restored to Online.
*
* @return It should report SUCCESS if successful and FAILURE otherwise.
*/
virtual Protocols::InteractionModel::Status CancelPowerAdjustRequest() = 0;
/**
* @brief Delegate for the ESA SHALL update its Forecast attribute with the RequestedStartTime including a new ForecastID.
*
* If the ESA supports ForecastAdjustment, and the ESAState is not UserOptOut and the RequestedStartTime is after
* the EarliestStartTime and the resulting EndTime is before the LatestEndTime, then ESA SHALL accept the request
* to modify the Start Time.
* A client can estimate the entire Forecast sequence duration by computing the EndTime - StartTime fields from the
* Forecast attribute, and therefore avoid scheduling the start time too late.
*
* @param requestedStartTime The requested start time in UTC that the client would like the appliance to shift its power
* forecast to.
* @param cause Who (Grid/local) is triggering this change.
*
* @return Success if the StartTime in the Forecast is updated, otherwise the command SHALL be rejected with appropriate
* IM_Status.
*/
virtual Protocols::InteractionModel::Status StartTimeAdjustRequest(const uint32_t requestedStartTime,
AdjustmentCauseEnum cause) = 0;
/**
* @brief Delegate handler for PauseRequest command
*
* If the ESA supports FA and the SlotIsPauseable field is true in the ActiveSlotNumber
* index in the Slots list, and the ESAState is not UserOptOut then the ESA SHALL allow its current
* operation to be Paused.
*
* During this state the ESA SHALL not consume or produce significant power (other than required to keep its
* basic control system operational).
*
* @param duration Duration that the ESA SHALL be paused for.
* @return Success if the ESA is paused, otherwise returns other IM_Status.
*/
virtual Protocols::InteractionModel::Status PauseRequest(const uint32_t duration, AdjustmentCauseEnum cause) = 0;
/**
* @brief Delegate handler for ResumeRequest command
*
* If the ESA supports FA and it is currently Paused then the ESA SHALL resume its operation.
* The ESA SHALL also generate a Resumed Event and the ESAState SHALL be updated accordingly to
* reflect its current state.
*
* @return Success if the ESA is resumed, otherwise returns other IM_Status.
*/
virtual Protocols::InteractionModel::Status ResumeRequest() = 0;
/**
* @brief Delegate handler for ModifyForecastRequest
*
* If the ESA supports FA, and the ESAState is not UserOptOut it SHALL attempt to adjust its power forecast.
* This allows a one or more modifications in a single command by sending a list of modifications (one for each 'slot').
* Attempts to modify slots which have already past, SHALL result in the entire command being rejected.
* If the ESA accepts the requested Forecast then it SHALL update its Forecast attribute (incrementing its ForecastID)
* and run the revised Forecast as its new intended operation.
*
* @param forecastID Indicates the ESA ForecastID that is to be modified.
* @param slotAdjustments List of adjustments to be applied to the ESA, corresponding to the expected ESA forecastID.
* @return Success if the entire list of SlotAdjustmentStruct are accepted, otherwise the command
* SHALL be rejected returning other IM_Status.
*/
virtual Protocols::InteractionModel::Status
ModifyForecastRequest(const uint32_t forecastID,
const DataModel::DecodableList<Structs::SlotAdjustmentStruct::Type> & slotAdjustments,
AdjustmentCauseEnum cause) = 0;
/**
* @brief Delegate handler for RequestConstraintBasedForecast
*
* The ESA SHALL inspect the requested power limits to ensure that there are no overlapping elements. The ESA
* manufacturer may also reject the request if it could cause the user’s preferences to be breached (e.g. may
* cause the home to be too hot or too cold, or a battery to be insufficiently charged).
* If the ESA can meet the requested power limits, it SHALL regenerate a new Power Forecast with a new ForecastID.
*
* @param constraints Sequence of turn up/down power requests that the ESA is being asked to constrain its operation within.
* @return Success if successful, otherwise the command SHALL be rejected returning other IM_Status.
*/
virtual Protocols::InteractionModel::Status
RequestConstraintBasedForecast(const DataModel::DecodableList<Structs::ConstraintsStruct::Type> & constraints,
AdjustmentCauseEnum cause) = 0;
/**
* @brief Delegate handler for CancelRequest
*
* The ESA SHALL attempt to cancel the effects of any previous adjustment request commands, and re-evaluate its
* forecast for intended operation ignoring those previous requests.
*
* If the ESA ForecastStruct ForecastUpdateReason was already `Internal Optimization`, then the command SHALL
* be rejected with FAILURE.
*
* If the command is accepted, the ESA SHALL update its ESAState if required, and the command status returned
* SHALL be SUCCESS.
*
* The ESA SHALL update its Forecast attribute to match its new intended operation, and update the
* ForecastStruct.ForecastUpdateReason to `Internal Optimization`
*
* @return Success if successful, otherwise the command SHALL be rejected returning other IM_Status.
*/
virtual Protocols::InteractionModel::Status CancelRequest() = 0;
// ------------------------------------------------------------------
// Get attribute methods
virtual ESATypeEnum GetESAType() = 0;
virtual bool GetESACanGenerate() = 0;
virtual ESAStateEnum GetESAState() = 0;
virtual int64_t GetAbsMinPower() = 0;
virtual int64_t GetAbsMaxPower() = 0;
virtual OptOutStateEnum GetOptOutState() = 0;
/**
* @brief Returns the current PowerAdjustCapability object
*
* The reference returned from GetPowerAdjustmentCapability() is only valid until the next Matter event
* is processed. Callers must not hold on to that reference for any asynchronous processing.
*
* Once another Matter event has had a chance to run, the memory associated with the
* PowerAdjustCapabilityStruct is likely to change or be re-allocated, so would become invalid.
*
* @return The current PowerAdjustCapability object
*/
virtual const DataModel::Nullable<Structs::PowerAdjustCapabilityStruct::Type> & GetPowerAdjustmentCapability() = 0;
/**
* @brief Returns the current Forecast object
*
* The reference returned from GetForecast() is only valid until the next Matter event
* is processed. Callers must not hold on to that reference for any asynchronous processing.
*
* Once another Matter event has had a chance to run, the memory associated with the
* ForecastStruct is likely to change or be re-allocated, so would become invalid.
*
* @return The current Forecast object
*/
virtual const DataModel::Nullable<Structs::ForecastStruct::Type> & GetForecast() = 0;
// ------------------------------------------------------------------
// Set attribute methods
virtual CHIP_ERROR SetESAState(ESAStateEnum) = 0;
protected:
EndpointId mEndpointId = 0;
};
class Instance : public AttributeAccessInterface, public CommandHandlerInterface
{
public:
Instance(EndpointId aEndpointId, Delegate & aDelegate, Feature aFeature) :
AttributeAccessInterface(MakeOptional(aEndpointId), Id), CommandHandlerInterface(MakeOptional(aEndpointId), Id),
mDelegate(aDelegate), mFeature(aFeature)
{
/* set the base class delegates endpointId */
mDelegate.SetEndpointId(aEndpointId);
}
~Instance() { Shutdown(); }
CHIP_ERROR Init();
void Shutdown();
bool HasFeature(Feature aFeature) const;
private:
Protocols::InteractionModel::Status GetMatterEpochTimeFromUnixTime(uint32_t & currentUtcTime) const;
private:
Delegate & mDelegate;
BitMask<Feature> mFeature;
// AttributeAccessInterface
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
// NOTE there are no writable attributes
// CommandHandlerInterface
void InvokeCommand(HandlerContext & handlerContext) override;
CHIP_ERROR EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) override;
Protocols::InteractionModel::Status CheckOptOutAllowsRequest(AdjustmentCauseEnum adjustmentCause);
void HandlePowerAdjustRequest(HandlerContext & ctx, const Commands::PowerAdjustRequest::DecodableType & commandData);
void HandleCancelPowerAdjustRequest(HandlerContext & ctx,
const Commands::CancelPowerAdjustRequest::DecodableType & commandData);
void HandleStartTimeAdjustRequest(HandlerContext & ctx, const Commands::StartTimeAdjustRequest::DecodableType & commandData);
void HandlePauseRequest(HandlerContext & ctx, const Commands::PauseRequest::DecodableType & commandData);
void HandleResumeRequest(HandlerContext & ctx, const Commands::ResumeRequest::DecodableType & commandData);
void HandleModifyForecastRequest(HandlerContext & ctx, const Commands::ModifyForecastRequest::DecodableType & commandData);
void HandleRequestConstraintBasedForecast(HandlerContext & ctx,
const Commands::RequestConstraintBasedForecast::DecodableType & commandData);
void HandleCancelRequest(HandlerContext & ctx, const Commands::CancelRequest::DecodableType & commandData);
};
} // namespace DeviceEnergyManagement
} // namespace Clusters
} // namespace app
} // namespace chip