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