/* * * 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 #include #include #include #include #include #include #include #include #include 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 & 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 & 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 & 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 & 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 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