29
29
#include < app/InteractionModelEngine.h>
30
30
#include < app/reporting/reporting.h>
31
31
#include < app/util/attribute-storage.h>
32
+ #include < lib/support/logging/CHIPLogging.h>
32
33
33
34
using namespace chip ;
34
35
using namespace chip ::app;
@@ -43,6 +44,9 @@ Instance::Instance(Delegate * aDelegate, EndpointId aEndpointId, ClusterId aClus
43
44
mDelegate(aDelegate), mEndpointId(aEndpointId), mClusterId(aClusterId)
44
45
{
45
46
mDelegate ->SetInstance (this );
47
+ mCountdownTime .policy ()
48
+ .Set (QuieterReportingPolicyEnum::kMarkDirtyOnIncrement )
49
+ .Set (QuieterReportingPolicyEnum::kMarkDirtyOnChangeToFromZero );
46
50
}
47
51
48
52
Instance::Instance (Delegate * aDelegate, EndpointId aEndpointId) : Instance(aDelegate, aEndpointId, OperationalState::Id) {}
@@ -84,6 +88,7 @@ CHIP_ERROR Instance::SetCurrentPhase(const DataModel::Nullable<uint8_t> & aPhase
84
88
if (mCurrentPhase != oldPhase)
85
89
{
86
90
MatterReportingAttributeChangeCallback (mEndpointId , mClusterId , Attributes::CurrentPhase::Id);
91
+ UpdateCountdownTimeFromClusterLogic ();
87
92
}
88
93
return CHIP_NO_ERROR;
89
94
}
@@ -96,9 +101,11 @@ CHIP_ERROR Instance::SetOperationalState(uint8_t aOpState)
96
101
return CHIP_ERROR_INVALID_ARGUMENT;
97
102
}
98
103
104
+ bool countdownTimeUpdateNeeded = false ;
99
105
if (mOperationalError .errorStateID != to_underlying (ErrorStateEnum::kNoError ))
100
106
{
101
107
mOperationalError .Set (to_underlying (ErrorStateEnum::kNoError ));
108
+ countdownTimeUpdateNeeded = true ;
102
109
MatterReportingAttributeChangeCallback (mEndpointId , mClusterId , Attributes::OperationalError::Id);
103
110
}
104
111
@@ -107,6 +114,12 @@ CHIP_ERROR Instance::SetOperationalState(uint8_t aOpState)
107
114
if (mOperationalState != oldState)
108
115
{
109
116
MatterReportingAttributeChangeCallback (mEndpointId , mClusterId , Attributes::OperationalState::Id);
117
+ countdownTimeUpdateNeeded = true ;
118
+ }
119
+
120
+ if (countdownTimeUpdateNeeded)
121
+ {
122
+ UpdateCountdownTimeFromClusterLogic ();
110
123
}
111
124
return CHIP_NO_ERROR;
112
125
}
@@ -143,6 +156,8 @@ void Instance::OnOperationalErrorDetected(const Structs::ErrorStateStruct::Type
143
156
MatterReportingAttributeChangeCallback (mEndpointId , mClusterId , Attributes::OperationalError::Id);
144
157
}
145
158
159
+ UpdateCountdownTimeFromClusterLogic ();
160
+
146
161
// Generate an ErrorDetected event
147
162
GenericErrorEvent event (mClusterId , aError);
148
163
EventNumber eventNumber;
@@ -156,7 +171,7 @@ void Instance::OnOperationalErrorDetected(const Structs::ErrorStateStruct::Type
156
171
157
172
void Instance::OnOperationCompletionDetected (uint8_t aCompletionErrorCode,
158
173
const Optional<DataModel::Nullable<uint32_t >> & aTotalOperationalTime,
159
- const Optional<DataModel::Nullable<uint32_t >> & aPausedTime) const
174
+ const Optional<DataModel::Nullable<uint32_t >> & aPausedTime)
160
175
{
161
176
ChipLogDetail (Zcl, " OperationalStateServer: OnOperationCompletionDetected" );
162
177
@@ -169,6 +184,8 @@ void Instance::OnOperationCompletionDetected(uint8_t aCompletionErrorCode,
169
184
ChipLogError (Zcl, " OperationalStateServer: Failed to record OperationCompletion event: %" CHIP_ERROR_FORMAT,
170
185
error.Format ());
171
186
}
187
+
188
+ UpdateCountdownTimeFromClusterLogic ();
172
189
}
173
190
174
191
void Instance::ReportOperationalStateListChange ()
@@ -179,6 +196,43 @@ void Instance::ReportOperationalStateListChange()
179
196
void Instance::ReportPhaseListChange ()
180
197
{
181
198
MatterReportingAttributeChangeCallback (ConcreteAttributePath (mEndpointId , mClusterId , Attributes::PhaseList::Id));
199
+ UpdateCountdownTimeFromClusterLogic ();
200
+ }
201
+
202
+ void Instance::UpdateCountdownTime (bool fromDelegate)
203
+ {
204
+ app::DataModel::Nullable<uint32_t > newCountdownTime = mDelegate ->GetCountdownTime ();
205
+ auto now = System::SystemClock ().GetMonotonicTimestamp ();
206
+
207
+ bool markDirty = false ;
208
+
209
+ if (fromDelegate)
210
+ {
211
+ // Updates from delegate are reduce-reported to every 10s max (choice of this implementation), in addition
212
+ // to default change-from-null, change-from-zero and increment policy.
213
+ auto predicate = [](const decltype (mCountdownTime )::SufficientChangePredicateCandidate & candidate) -> bool {
214
+ if (candidate.lastDirtyValue .IsNull () || candidate.newValue .IsNull ())
215
+ {
216
+ return false ;
217
+ }
218
+
219
+ uint32_t lastDirtyValue = candidate.lastDirtyValue .Value ();
220
+ uint32_t newValue = candidate.newValue .Value ();
221
+ uint32_t kNumSecondsDeltaToReport = 10 ;
222
+ return (newValue < lastDirtyValue) && ((lastDirtyValue - newValue) > kNumSecondsDeltaToReport );
223
+ };
224
+ markDirty = (mCountdownTime .SetValue (newCountdownTime, now, predicate) == AttributeDirtyState::kMustReport );
225
+ }
226
+ else
227
+ {
228
+ auto predicate = [](const decltype (mCountdownTime )::SufficientChangePredicateCandidate &) -> bool { return true ; };
229
+ markDirty = (mCountdownTime .SetValue (newCountdownTime, now, predicate) == AttributeDirtyState::kMustReport );
230
+ }
231
+
232
+ if (markDirty)
233
+ {
234
+ MatterReportingAttributeChangeCallback (mEndpointId , mClusterId , Attributes::CountdownTime::Id);
235
+ }
182
236
}
183
237
184
238
bool Instance::IsSupportedPhase (uint8_t aPhase)
@@ -270,6 +324,7 @@ void Instance::InvokeCommand(HandlerContext & handlerContext)
270
324
ChipLogDetail (Zcl, " OperationalState: Entering handling derived cluster commands" );
271
325
272
326
InvokeDerivedClusterCommand (handlerContext);
327
+ break ;
273
328
}
274
329
}
275
330
@@ -294,18 +349,18 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu
294
349
}
295
350
return err;
296
351
});
352
+ break ;
297
353
}
298
- break ;
299
354
300
355
case OperationalState::Attributes::OperationalState::Id: {
301
356
ReturnErrorOnFailure (aEncoder.Encode (GetCurrentOperationalState ()));
357
+ break ;
302
358
}
303
- break ;
304
359
305
360
case OperationalState::Attributes::OperationalError::Id: {
306
361
ReturnErrorOnFailure (aEncoder.Encode (mOperationalError ));
362
+ break ;
307
363
}
308
- break ;
309
364
310
365
case OperationalState::Attributes::PhaseList::Id: {
311
366
@@ -332,18 +387,19 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu
332
387
ReturnErrorOnFailure (encoder.Encode (phase2));
333
388
}
334
389
});
390
+ break ;
335
391
}
336
- break ;
337
392
338
393
case OperationalState::Attributes::CurrentPhase::Id: {
339
394
ReturnErrorOnFailure (aEncoder.Encode (GetCurrentPhase ()));
395
+ break ;
340
396
}
341
- break ;
342
397
343
398
case OperationalState::Attributes::CountdownTime::Id: {
399
+ // Read through to get value closest to reality.
344
400
ReturnErrorOnFailure (aEncoder.Encode (mDelegate ->GetCountdownTime ()));
401
+ break ;
345
402
}
346
- break ;
347
403
}
348
404
return CHIP_NO_ERROR;
349
405
}
0 commit comments