/src/connectedhomeip/src/app/clusters/smoke-co-alarm-server/SmokeCoAlarmCluster.cpp
Line | Count | Source |
1 | | /** |
2 | | * |
3 | | * Copyright (c) 2023 Project CHIP Authors |
4 | | * |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | * |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | * |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | |
18 | | #include "SmokeCoAlarmCluster.h" |
19 | | #include <app/server-cluster/AttributeListBuilder.h> |
20 | | #include <clusters/SmokeCoAlarm/Metadata.h> |
21 | | |
22 | | using namespace chip::app::Clusters::SmokeCoAlarm; |
23 | | using namespace chip::app::Clusters::SmokeCoAlarm::Attributes; |
24 | | using chip::Protocols::InteractionModel::Status; |
25 | | |
26 | | namespace chip { |
27 | | namespace app { |
28 | | namespace Clusters { |
29 | | |
30 | 0 | SmokeCoAlarmCluster::SmokeCoAlarmCluster(EndpointId endpointId) : SmokeCoAlarmCluster(endpointId, Config{}) {} |
31 | | |
32 | | SmokeCoAlarmCluster::SmokeCoAlarmCluster(EndpointId endpointId, const Config & config) : |
33 | 0 | DefaultServerCluster({ endpointId, Id }), mConfig(config), mInoperativeWhenUnmounted(config.inoperativeWhenUnmounted) |
34 | 0 | {} |
35 | | |
36 | | bool SmokeCoAlarmCluster::SetSmokeState(AlarmStateEnum newSmokeState) |
37 | 0 | { |
38 | 0 | VerifyOrReturnValue(SupportsSmokeAlarm(), false); |
39 | 0 | if (!SetAttributeValue(mSmokeState, newSmokeState, SmokeState::Id)) |
40 | 0 | { |
41 | 0 | return true; |
42 | 0 | } |
43 | | |
44 | 0 | if (mContext != nullptr && (newSmokeState == AlarmStateEnum::kWarning || newSmokeState == AlarmStateEnum::kCritical)) |
45 | 0 | { |
46 | 0 | Events::SmokeAlarm::Type event{ newSmokeState }; |
47 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
48 | 0 | } |
49 | |
|
50 | 0 | if (newSmokeState == AlarmStateEnum::kCritical) |
51 | 0 | { |
52 | 0 | SetDeviceMuted(MuteStateEnum::kNotMuted); |
53 | 0 | } |
54 | |
|
55 | 0 | return true; |
56 | 0 | } |
57 | | |
58 | | bool SmokeCoAlarmCluster::SetCOState(AlarmStateEnum newCOState) |
59 | 0 | { |
60 | 0 | VerifyOrReturnValue(SupportsCOAlarm(), false); |
61 | 0 | if (!SetAttributeValue(mCOState, newCOState, COState::Id)) |
62 | 0 | { |
63 | 0 | return true; |
64 | 0 | } |
65 | | |
66 | 0 | if (mContext != nullptr && (newCOState == AlarmStateEnum::kWarning || newCOState == AlarmStateEnum::kCritical)) |
67 | 0 | { |
68 | 0 | Events::COAlarm::Type event{ newCOState }; |
69 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
70 | 0 | } |
71 | |
|
72 | 0 | if (newCOState == AlarmStateEnum::kCritical) |
73 | 0 | { |
74 | 0 | SetDeviceMuted(MuteStateEnum::kNotMuted); |
75 | 0 | } |
76 | |
|
77 | 0 | return true; |
78 | 0 | } |
79 | | |
80 | | void SmokeCoAlarmCluster::SetBatteryAlert(AlarmStateEnum newBatteryAlert) |
81 | 0 | { |
82 | 0 | if (!SetAttributeValue(mBatteryAlert, newBatteryAlert, BatteryAlert::Id)) |
83 | 0 | { |
84 | 0 | return; |
85 | 0 | } |
86 | | |
87 | 0 | if (mContext != nullptr && (newBatteryAlert == AlarmStateEnum::kWarning || newBatteryAlert == AlarmStateEnum::kCritical)) |
88 | 0 | { |
89 | 0 | Events::LowBattery::Type event{ newBatteryAlert }; |
90 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
91 | 0 | } |
92 | |
|
93 | 0 | if (newBatteryAlert == AlarmStateEnum::kCritical) |
94 | 0 | { |
95 | 0 | SetDeviceMuted(MuteStateEnum::kNotMuted); |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | bool SmokeCoAlarmCluster::SetDeviceMuted(MuteStateEnum newDeviceMuted) |
100 | 0 | { |
101 | 0 | VerifyOrReturnValue(mConfig.optionalAttribs.IsSet(DeviceMuted::Id), false); |
102 | 0 | if (mDeviceMuted == newDeviceMuted) |
103 | 0 | { |
104 | 0 | return true; |
105 | 0 | } |
106 | | |
107 | 0 | if (newDeviceMuted == MuteStateEnum::kMuted) |
108 | 0 | { |
109 | | // Cannot mute while any alarm is in Critical state. |
110 | | // All alarm state members are always present and default to kNormal |
111 | 0 | VerifyOrReturnValue(mSmokeState != AlarmStateEnum::kCritical, false); |
112 | 0 | VerifyOrReturnValue(mCOState != AlarmStateEnum::kCritical, false); |
113 | 0 | VerifyOrReturnValue(mBatteryAlert != AlarmStateEnum::kCritical, false); |
114 | 0 | VerifyOrReturnValue(mInterconnectSmokeAlarm != AlarmStateEnum::kCritical, false); |
115 | 0 | VerifyOrReturnValue(mInterconnectCOAlarm != AlarmStateEnum::kCritical, false); |
116 | 0 | } |
117 | | |
118 | 0 | SetAttributeValue(mDeviceMuted, newDeviceMuted, DeviceMuted::Id); |
119 | |
|
120 | 0 | if (mContext != nullptr) |
121 | 0 | { |
122 | 0 | if (newDeviceMuted == MuteStateEnum::kMuted) |
123 | 0 | { |
124 | 0 | Events::AlarmMuted::Type event{}; |
125 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
126 | 0 | } |
127 | 0 | else if (newDeviceMuted == MuteStateEnum::kNotMuted) |
128 | 0 | { |
129 | 0 | Events::MuteEnded::Type event{}; |
130 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
131 | 0 | } |
132 | 0 | } |
133 | |
|
134 | 0 | return true; |
135 | 0 | } |
136 | | |
137 | | void SmokeCoAlarmCluster::SetTestInProgress(bool newTestInProgress) |
138 | 0 | { |
139 | 0 | if (!SetAttributeValue(mTestInProgress, newTestInProgress, TestInProgress::Id)) |
140 | 0 | { |
141 | 0 | return; |
142 | 0 | } |
143 | | |
144 | 0 | if (!newTestInProgress && mContext != nullptr) |
145 | 0 | { |
146 | 0 | Events::SelfTestComplete::Type event{}; |
147 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | void SmokeCoAlarmCluster::SetHardwareFaultAlert(bool newHardwareFaultAlert) |
152 | 0 | { |
153 | 0 | if (!SetAttributeValue(mHardwareFaultAlert, newHardwareFaultAlert, HardwareFaultAlert::Id)) |
154 | 0 | { |
155 | 0 | return; |
156 | 0 | } |
157 | | |
158 | 0 | if (newHardwareFaultAlert && mContext != nullptr) |
159 | 0 | { |
160 | 0 | Events::HardwareFault::Type event{}; |
161 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | | void SmokeCoAlarmCluster::SetEndOfServiceAlert(EndOfServiceEnum newEndOfServiceAlert) |
166 | 0 | { |
167 | 0 | if (!SetAttributeValue(mEndOfServiceAlert, newEndOfServiceAlert, EndOfServiceAlert::Id)) |
168 | 0 | { |
169 | 0 | return; |
170 | 0 | } |
171 | | |
172 | 0 | if (newEndOfServiceAlert == EndOfServiceEnum::kExpired && mContext != nullptr) |
173 | 0 | { |
174 | 0 | Events::EndOfService::Type event{}; |
175 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | | bool SmokeCoAlarmCluster::SetInterconnectSmokeAlarm(AlarmStateEnum newInterconnectSmokeAlarm) |
180 | 0 | { |
181 | 0 | VerifyOrReturnValue(mConfig.optionalAttribs.IsSet(InterconnectSmokeAlarm::Id), false); |
182 | 0 | if (!SetAttributeValue(mInterconnectSmokeAlarm, newInterconnectSmokeAlarm, InterconnectSmokeAlarm::Id)) |
183 | 0 | { |
184 | 0 | return true; |
185 | 0 | } |
186 | | |
187 | 0 | if (mContext != nullptr && |
188 | 0 | (newInterconnectSmokeAlarm == AlarmStateEnum::kWarning || newInterconnectSmokeAlarm == AlarmStateEnum::kCritical)) |
189 | 0 | { |
190 | 0 | Events::InterconnectSmokeAlarm::Type event{ newInterconnectSmokeAlarm }; |
191 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
192 | 0 | } |
193 | |
|
194 | 0 | if (newInterconnectSmokeAlarm == AlarmStateEnum::kCritical) |
195 | 0 | { |
196 | 0 | SetDeviceMuted(MuteStateEnum::kNotMuted); |
197 | 0 | } |
198 | |
|
199 | 0 | return true; |
200 | 0 | } |
201 | | |
202 | | bool SmokeCoAlarmCluster::SetInterconnectCOAlarm(AlarmStateEnum newInterconnectCOAlarm) |
203 | 0 | { |
204 | 0 | VerifyOrReturnValue(mConfig.optionalAttribs.IsSet(InterconnectCOAlarm::Id), false); |
205 | 0 | if (!SetAttributeValue(mInterconnectCOAlarm, newInterconnectCOAlarm, InterconnectCOAlarm::Id)) |
206 | 0 | { |
207 | 0 | return true; |
208 | 0 | } |
209 | | |
210 | 0 | if (mContext != nullptr && |
211 | 0 | (newInterconnectCOAlarm == AlarmStateEnum::kWarning || newInterconnectCOAlarm == AlarmStateEnum::kCritical)) |
212 | 0 | { |
213 | 0 | Events::InterconnectCOAlarm::Type event{ newInterconnectCOAlarm }; |
214 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
215 | 0 | } |
216 | |
|
217 | 0 | if (newInterconnectCOAlarm == AlarmStateEnum::kCritical) |
218 | 0 | { |
219 | 0 | SetDeviceMuted(MuteStateEnum::kNotMuted); |
220 | 0 | } |
221 | |
|
222 | 0 | return true; |
223 | 0 | } |
224 | | |
225 | | void SmokeCoAlarmCluster::SetContaminationState(ContaminationStateEnum newContaminationState) |
226 | 0 | { |
227 | 0 | VerifyOrReturn(SupportsSmokeAlarm()); |
228 | 0 | SetAttributeValue(mContaminationState, newContaminationState, ContaminationState::Id); |
229 | 0 | } |
230 | | |
231 | | void SmokeCoAlarmCluster::SetSmokeSensitivityLevel(SensitivityEnum newSmokeSensitivityLevel) |
232 | 0 | { |
233 | 0 | VerifyOrReturn(SupportsSmokeAlarm()); |
234 | 0 | SetAttributeValue(mSmokeSensitivityLevel, newSmokeSensitivityLevel, SmokeSensitivityLevel::Id); |
235 | 0 | if (mDelegate != nullptr) |
236 | 0 | { |
237 | 0 | mDelegate->OnSmokeSensitivityLevelChanged(newSmokeSensitivityLevel); |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | | void SmokeCoAlarmCluster::SetExpiryDate(uint32_t newExpiryDate) |
242 | 0 | { |
243 | 0 | VerifyOrReturn(mConfig.optionalAttribs.IsSet(ExpiryDate::Id)); |
244 | 0 | SetAttributeValue(mExpiryDate, newExpiryDate, ExpiryDate::Id); |
245 | 0 | } |
246 | | |
247 | | bool SmokeCoAlarmCluster::SetUnmountedState(bool isUnmounted) |
248 | 0 | { |
249 | 0 | VerifyOrReturnValue(mConfig.optionalAttribs.IsSet(Unmounted::Id), false); |
250 | 0 | if (!SetAttributeValue(mUnmounted, isUnmounted, Unmounted::Id)) |
251 | 0 | { |
252 | 0 | return true; |
253 | 0 | } |
254 | | |
255 | 0 | if (mInoperativeWhenUnmounted) |
256 | 0 | { |
257 | 0 | if (isUnmounted) |
258 | 0 | { |
259 | 0 | SetExpressedState(ExpressedStateEnum::kInoperative); |
260 | 0 | } |
261 | 0 | else if (mExpressedState == ExpressedStateEnum::kInoperative) |
262 | 0 | { |
263 | 0 | SetExpressedState(ExpressedStateEnum::kNormal); |
264 | 0 | } |
265 | 0 | } |
266 | |
|
267 | 0 | return true; |
268 | 0 | } |
269 | | |
270 | | void SmokeCoAlarmCluster::SetExpressedStateByPriority(const std::array<ExpressedStateEnum, kPriorityOrderLength> & priorityOrder) |
271 | 0 | { |
272 | 0 | for (ExpressedStateEnum priority : priorityOrder) |
273 | 0 | { |
274 | 0 | AlarmStateEnum alarmState = AlarmStateEnum::kNormal; |
275 | 0 | EndOfServiceEnum endOfServiceState = EndOfServiceEnum::kNormal; |
276 | 0 | bool active = false; |
277 | 0 | bool unmounted = false; |
278 | |
|
279 | 0 | switch (priority) |
280 | 0 | { |
281 | 0 | case ExpressedStateEnum::kSmokeAlarm: |
282 | 0 | alarmState = GetSmokeState(); |
283 | 0 | break; |
284 | 0 | case ExpressedStateEnum::kCOAlarm: |
285 | 0 | alarmState = GetCOState(); |
286 | 0 | break; |
287 | 0 | case ExpressedStateEnum::kBatteryAlert: |
288 | 0 | alarmState = GetBatteryAlert(); |
289 | 0 | break; |
290 | 0 | case ExpressedStateEnum::kTesting: |
291 | 0 | active = GetTestInProgress(); |
292 | 0 | break; |
293 | 0 | case ExpressedStateEnum::kHardwareFault: |
294 | 0 | active = GetHardwareFaultAlert(); |
295 | 0 | break; |
296 | 0 | case ExpressedStateEnum::kEndOfService: |
297 | 0 | endOfServiceState = GetEndOfServiceAlert(); |
298 | 0 | break; |
299 | 0 | case ExpressedStateEnum::kInterconnectSmoke: |
300 | 0 | alarmState = GetInterconnectSmokeAlarm(); |
301 | 0 | break; |
302 | 0 | case ExpressedStateEnum::kInterconnectCO: |
303 | 0 | alarmState = GetInterconnectCOAlarm(); |
304 | 0 | break; |
305 | 0 | case ExpressedStateEnum::kInoperative: |
306 | 0 | unmounted = GetUnmountedState(); |
307 | 0 | break; |
308 | 0 | default: |
309 | 0 | break; |
310 | 0 | } |
311 | | |
312 | 0 | if ((alarmState != AlarmStateEnum::kNormal) || (endOfServiceState != EndOfServiceEnum::kNormal) || active || unmounted) |
313 | 0 | { |
314 | 0 | SetExpressedState(priority); |
315 | 0 | return; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | 0 | SetExpressedState(ExpressedStateEnum::kNormal); |
320 | 0 | } |
321 | | |
322 | | bool SmokeCoAlarmCluster::RequestSelfTest() |
323 | 0 | { |
324 | 0 | if (mExpressedState == ExpressedStateEnum::kSmokeAlarm || mExpressedState == ExpressedStateEnum::kCOAlarm || |
325 | 0 | mExpressedState == ExpressedStateEnum::kTesting || mExpressedState == ExpressedStateEnum::kInterconnectSmoke || |
326 | 0 | mExpressedState == ExpressedStateEnum::kInterconnectCO) |
327 | 0 | { |
328 | 0 | return false; |
329 | 0 | } |
330 | | |
331 | 0 | SetTestInProgress(true); |
332 | 0 | SetExpressedState(ExpressedStateEnum::kTesting); |
333 | 0 | if (mDelegate != nullptr) |
334 | 0 | { |
335 | 0 | mDelegate->OnSelfTestRequested(); |
336 | 0 | } |
337 | 0 | return true; |
338 | 0 | } |
339 | | |
340 | | DataModel::ActionReturnStatus SmokeCoAlarmCluster::ReadAttribute(const DataModel::ReadAttributeRequest & request, |
341 | | AttributeValueEncoder & encoder) |
342 | 0 | { |
343 | 0 | switch (request.path.mAttributeId) |
344 | 0 | { |
345 | 0 | case ClusterRevision::Id: |
346 | 0 | return encoder.Encode(SmokeCoAlarm::kRevision); |
347 | 0 | case FeatureMap::Id: |
348 | 0 | return encoder.Encode(mConfig.featureMap); |
349 | 0 | case ExpressedState::Id: |
350 | 0 | return encoder.Encode(mExpressedState); |
351 | 0 | case SmokeState::Id: |
352 | 0 | return encoder.Encode(mSmokeState); |
353 | 0 | case COState::Id: |
354 | 0 | return encoder.Encode(mCOState); |
355 | 0 | case BatteryAlert::Id: |
356 | 0 | return encoder.Encode(mBatteryAlert); |
357 | 0 | case DeviceMuted::Id: |
358 | 0 | return encoder.Encode(mDeviceMuted); |
359 | 0 | case TestInProgress::Id: |
360 | 0 | return encoder.Encode(mTestInProgress); |
361 | 0 | case HardwareFaultAlert::Id: |
362 | 0 | return encoder.Encode(mHardwareFaultAlert); |
363 | 0 | case EndOfServiceAlert::Id: |
364 | 0 | return encoder.Encode(mEndOfServiceAlert); |
365 | 0 | case InterconnectSmokeAlarm::Id: |
366 | 0 | return encoder.Encode(mInterconnectSmokeAlarm); |
367 | 0 | case InterconnectCOAlarm::Id: |
368 | 0 | return encoder.Encode(mInterconnectCOAlarm); |
369 | 0 | case ContaminationState::Id: |
370 | 0 | return encoder.Encode(mContaminationState); |
371 | 0 | case SmokeSensitivityLevel::Id: |
372 | 0 | return encoder.Encode(mSmokeSensitivityLevel); |
373 | 0 | case ExpiryDate::Id: |
374 | 0 | return encoder.Encode(mExpiryDate); |
375 | 0 | case Unmounted::Id: |
376 | 0 | return encoder.Encode(mUnmounted); |
377 | 0 | default: |
378 | 0 | return Status::UnsupportedAttribute; |
379 | 0 | } |
380 | 0 | } |
381 | | |
382 | | DataModel::ActionReturnStatus SmokeCoAlarmCluster::WriteAttribute(const DataModel::WriteAttributeRequest & request, |
383 | | AttributeValueDecoder & decoder) |
384 | 0 | { |
385 | 0 | if (request.path.mAttributeId != SmokeSensitivityLevel::Id) |
386 | 0 | { |
387 | 0 | return Status::UnsupportedWrite; |
388 | 0 | } |
389 | | |
390 | 0 | SensitivityEnum value; |
391 | 0 | ReturnErrorOnFailure(decoder.Decode(value)); |
392 | 0 | SetSmokeSensitivityLevel(value); |
393 | 0 | return Status::Success; |
394 | 0 | } |
395 | | |
396 | | CHIP_ERROR SmokeCoAlarmCluster::Attributes(const ConcreteClusterPath & path, |
397 | | ReadOnlyBufferBuilder<DataModel::AttributeEntry> & builder) |
398 | 0 | { |
399 | 0 | AttributeListBuilder listBuilder(builder); |
400 | |
|
401 | 0 | const AttributeListBuilder::OptionalAttributeEntry optionalAttributes[] = { |
402 | 0 | { mConfig.featureMap.Has(Feature::kSmokeAlarm), SmokeState::kMetadataEntry }, |
403 | 0 | { mConfig.featureMap.Has(Feature::kCoAlarm), COState::kMetadataEntry }, |
404 | 0 | { mConfig.optionalAttribs.IsSet(DeviceMuted::Id), DeviceMuted::kMetadataEntry }, |
405 | 0 | { mConfig.optionalAttribs.IsSet(InterconnectSmokeAlarm::Id), InterconnectSmokeAlarm::kMetadataEntry }, |
406 | 0 | { mConfig.optionalAttribs.IsSet(InterconnectCOAlarm::Id), InterconnectCOAlarm::kMetadataEntry }, |
407 | 0 | { mConfig.featureMap.Has(Feature::kSmokeAlarm), ContaminationState::kMetadataEntry }, |
408 | 0 | { mConfig.featureMap.Has(Feature::kSmokeAlarm), SmokeSensitivityLevel::kMetadataEntry }, |
409 | 0 | { mConfig.optionalAttribs.IsSet(ExpiryDate::Id), ExpiryDate::kMetadataEntry }, |
410 | 0 | { mConfig.optionalAttribs.IsSet(Unmounted::Id), Unmounted::kMetadataEntry }, |
411 | 0 | }; |
412 | |
|
413 | 0 | return listBuilder.Append(Span(kMandatoryMetadata), Span(optionalAttributes)); |
414 | 0 | } |
415 | | |
416 | | std::optional<DataModel::ActionReturnStatus> SmokeCoAlarmCluster::InvokeCommand(const DataModel::InvokeRequest & request, |
417 | | chip::TLV::TLVReader & input_arguments, |
418 | | CommandHandler * handler) |
419 | 0 | { |
420 | 0 | switch (request.path.mCommandId) |
421 | 0 | { |
422 | 0 | case Commands::SelfTestRequest::Id: |
423 | 0 | return HandleRemoteSelfTestRequest(); |
424 | 0 | default: |
425 | 0 | return Status::UnsupportedCommand; |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | | CHIP_ERROR SmokeCoAlarmCluster::AcceptedCommands(const ConcreteClusterPath & path, |
430 | | ReadOnlyBufferBuilder<DataModel::AcceptedCommandEntry> & builder) |
431 | 0 | { |
432 | 0 | return builder.AppendElements({ Commands::SelfTestRequest::kMetadataEntry }); |
433 | 0 | } |
434 | | |
435 | | void SmokeCoAlarmCluster::SetExpressedState(ExpressedStateEnum newExpressedState) |
436 | 0 | { |
437 | 0 | if (!SetAttributeValue(mExpressedState, newExpressedState, ExpressedState::Id)) |
438 | 0 | { |
439 | 0 | return; |
440 | 0 | } |
441 | | |
442 | 0 | if (newExpressedState == ExpressedStateEnum::kNormal && mContext != nullptr) |
443 | 0 | { |
444 | 0 | Events::AllClear::Type event{}; |
445 | 0 | mContext->interactionContext.eventsGenerator.GenerateEvent(event, mPath.mEndpointId); |
446 | 0 | } |
447 | |
|
448 | 0 | if (mDelegate != nullptr) |
449 | 0 | { |
450 | 0 | mDelegate->OnExpressedStateChanged(newExpressedState); |
451 | 0 | } |
452 | 0 | } |
453 | | |
454 | | Status SmokeCoAlarmCluster::HandleRemoteSelfTestRequest() |
455 | 0 | { |
456 | 0 | if (mExpressedState == ExpressedStateEnum::kSmokeAlarm || mExpressedState == ExpressedStateEnum::kCOAlarm || |
457 | 0 | mExpressedState == ExpressedStateEnum::kTesting || mExpressedState == ExpressedStateEnum::kInterconnectSmoke || |
458 | 0 | mExpressedState == ExpressedStateEnum::kInterconnectCO) |
459 | 0 | { |
460 | 0 | return Status::Busy; |
461 | 0 | } |
462 | | |
463 | 0 | SetTestInProgress(true); |
464 | 0 | SetExpressedState(ExpressedStateEnum::kTesting); |
465 | 0 | if (mDelegate != nullptr) |
466 | 0 | { |
467 | 0 | mDelegate->OnSelfTestRequested(); |
468 | 0 | } |
469 | 0 | return Status::Success; |
470 | 0 | } |
471 | | |
472 | | } // namespace Clusters |
473 | | } // namespace app |
474 | | } // namespace chip |