forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDeviceEnergyManagementDelegateImpl.h
303 lines (263 loc) · 14.6 KB
/
DeviceEnergyManagementDelegateImpl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/*
*
* Copyright (c) 2023-2024 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/clusters/device-energy-management-server/device-energy-management-server.h>
#include <app/util/config.h>
namespace chip {
namespace app {
namespace Clusters {
namespace DeviceEnergyManagement {
class DEMManufacturerDelegate;
/**
* The application delegate.
*/
class DeviceEnergyManagementDelegate : public DeviceEnergyManagement::Delegate
{
public:
DeviceEnergyManagementDelegate();
void SetDeviceEnergyManagementInstance(DeviceEnergyManagement::Instance & instance);
void SetDEMManufacturerDelegate(DEMManufacturerDelegate & deviceEnergyManagementManufacturerDelegate);
/**
*
* Implement the DeviceEnergyManagement::Delegate interface
*
*/
/**
* @brief Implements 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.
*/
chip::Protocols::InteractionModel::Status PowerAdjustRequest(const int64_t powerMw, const uint32_t durationS,
AdjustmentCauseEnum cause) override;
/**
* @brief 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.
*/
chip::Protocols::InteractionModel::Status CancelPowerAdjustRequest() override;
/**
* @brief 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.
*/
chip::Protocols::InteractionModel::Status StartTimeAdjustRequest(const uint32_t requestedStartTimeUtc,
AdjustmentCauseEnum cause) override;
/**
* @brief 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.
*/
chip::Protocols::InteractionModel::Status PauseRequest(const uint32_t durationS, AdjustmentCauseEnum cause) override;
/**
* @brief 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.
*/
chip::Protocols::InteractionModel::Status ResumeRequest() override;
/**
* @brief 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.
*
* *** NOTE *** for the memory management of the forecast object, see the comment before the mForecast delaration below.
*
* @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.
*/
chip::Protocols::InteractionModel::Status
ModifyForecastRequest(const uint32_t forecastID,
const DataModel::DecodableList<Structs::SlotAdjustmentStruct::DecodableType> & slotAdjustments,
AdjustmentCauseEnum cause) override;
/**
* @brief 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.
*/
chip::Protocols::InteractionModel::Status
RequestConstraintBasedForecast(const DataModel::DecodableList<Structs::ConstraintsStruct::DecodableType> & constraints,
AdjustmentCauseEnum cause) override;
/**
* @brief 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.
*/
chip::Protocols::InteractionModel::Status CancelRequest() override;
// ------------------------------------------------------------------
// Overridden DeviceEnergyManagement::Delegate Get attribute methods
ESATypeEnum GetESAType() override;
bool GetESACanGenerate() override;
ESAStateEnum GetESAState() override;
int64_t GetAbsMinPower() override;
int64_t GetAbsMaxPower() override;
const DataModel::Nullable<Structs::PowerAdjustCapabilityStruct::Type> & GetPowerAdjustmentCapability() override;
const DataModel::Nullable<Structs::ForecastStruct::Type> & GetForecast() override;
OptOutStateEnum GetOptOutState() override;
// ------------------------------------------------------------------
// Overridden DeviceEnergyManagement::Delegate Set attribute methods
CHIP_ERROR SetESAState(ESAStateEnum) override;
// Local Set methods
CHIP_ERROR SetESAType(ESATypeEnum);
CHIP_ERROR SetESACanGenerate(bool);
CHIP_ERROR SetAbsMinPower(int64_t);
CHIP_ERROR SetAbsMaxPower(int64_t);
CHIP_ERROR SetPowerAdjustmentCapability(const DataModel::Nullable<Structs::PowerAdjustCapabilityStruct::Type> &);
// The DeviceEnergyManagementDelegate owns the master copy of the ForecastStruct object which is accessed via GetForecast and
// SetForecast. The slots field of forecast is owned and managed by the object that implements the DEMManufacturerDelegate
// interface. The slots memory MUST exist for the lifetime of the forecast object from where it is referenced.
//
// The rationale for this is as follows:
// It is envisioned there will be one master forecast object declared in DeviceEnergyManagementDelegate. When
// constructed, the field DataModel::List<const Structs::SlotStruct::Type> slots will be empty.
//
// The EVSEManufacturerImpl class (examples/energy-management-app/energy-management-common/include/EVSEManufacturerImpl.h) is
// an example implementation that a specific vendor can use as a template. It understands how the underlying energy appliance
// functions. EVSEManufacturerImpl inherits from DEMManufacturerDelegate
// (examples/energy-management-app/energy-management-common/include/DEMManufacturerDelegate.h) which is a generic interface
// and how the DeviceEnergyManagementDelegate class
// (examples/energy-management-app/energy-management-common/src/DeviceEnergyManagementDelegateImpl.cpp) communicates from the
// generic cluster world to the specific appliance implementation (EVSEManufacturerImpl).
//
// EVSEManufacturerImpl understands the slot structures of the appliance and configures the slot structures as follows:
//
// Call DeviceEnergyManagementDelegate::GetForecast() to get the current forecast
// Modify the slot structure - the slots memory is owned by EVSEManufacturerImpl
// Call DeviceEnergyManagementDelegate::GetForecast() to set the current forecast
//
//
// The cluster object DeviceEnergyManagement::Instance
// (src/app/clusters/device-energy-management-server/device-energy-management-server.cpp) only reads the slots field of
// forecast when checking commands (indeed it does not modify any forecast fields itself). The DeviceEnergyManagementDelegate
// object does modify some of forecast's fields but does NOT modify the slots field. The only command that can modify the
// slots field is HandleModifyForecastRequest. Whilst DeviceEnergyManagementDelegate::ModifyForecastRequest does some state
// checking, the slots field is only modified by the EVSEManufacturerImpl object via the call
// DEMManufacturerDelegate::HandleModifyForecastRequest. DEMManufacturerDelegate::HandleModifyForecastRequest may
// delete/allocate the slots memory but this will be done atomically in the call to
// DEMManufacturerDelegate::HandleModifyForecastRequest so the underlying memory is coherent => the call to
// DEMManufacturerDelegate::HandleModifyForecastRequest cannot be interrupted by any other CHIP task activity.
CHIP_ERROR SetForecast(const DataModel::Nullable<Structs::ForecastStruct::Type> &);
CHIP_ERROR SetOptOutState(OptOutStateEnum);
// Returns whether the DeviceEnergyManagement is supported
uint32_t HasFeature(Feature feature) const;
private:
/**
* @brief Handle a PowerAdjustRequest failing
*
* Cleans up the PowerAdjust state should the request fail
*/
void HandlePowerAdjustRequestFailure();
// Methods to handle when a PowerAdjustment completes
static void PowerAdjustTimerExpiry(System::Layer * systemLayer, void * delegate);
void HandlePowerAdjustTimerExpiry();
// Method to cancel a PowerAdjustment
CHIP_ERROR CancelPowerAdjustRequestAndGenerateEvent(CauseEnum cause);
// Method to generate a PowerAdjustEnd event
CHIP_ERROR GeneratePowerAdjustEndEvent(CauseEnum cause);
/**
* @brief Handle a PauseRequest failing
*
* Cleans up the state should the PauseRequest fail
*/
void HandlePauseRequestFailure();
// Methods to handle when a PauseRequest completes
static void PauseRequestTimerExpiry(System::Layer * systemLayer, void * delegate);
void HandlePauseRequestTimerExpiry();
// Method to cancel a PauseRequest
CHIP_ERROR CancelPauseRequestAndGenerateEvent(CauseEnum cause);
// Method to generate a Paused event
CHIP_ERROR GenerateResumedEvent(CauseEnum cause);
private:
// Have a pointer to partner instance object
DeviceEnergyManagement::Instance * mpDEMInstance;
// The DEMManufacturerDelegate object knows how to handle
// manufacturer/product specific operations
DEMManufacturerDelegate * mpDEMManufacturerDelegate;
// Various attributes
ESATypeEnum mEsaType;
bool mEsaCanGenerate;
ESAStateEnum mEsaState;
int64_t mAbsMinPowerMw;
int64_t mAbsMaxPowerMw;
OptOutStateEnum mOptOutState;
DataModel::Nullable<Structs::PowerAdjustCapabilityStruct::Type> mPowerAdjustCapabilityStruct;
// See note above on SetForecast() about mForecast memory management
DataModel::Nullable<Structs::ForecastStruct::Type> mForecast;
// Keep track whether a PowerAdjustment is in progress
bool mPowerAdjustmentInProgress;
// Keep track of when that PowerAdjustment started
uint32_t mPowerAdjustmentStartTimeUtc;
// Keep track whether a PauseRequest is in progress
bool mPauseRequestInProgress;
};
} // namespace DeviceEnergyManagement
} // namespace Clusters
} // namespace app
} // namespace chip