19
19
#include < controller/AutoCommissioner.h>
20
20
21
21
#include < app/InteractionModelTimeout.h>
22
+ #include < controller-clusters/zap-generated/CHIPClusters.h>
22
23
#include < controller/CHIPDeviceController.h>
23
24
#include < credentials/CHIPCert.h>
24
25
#include < lib/support/SafeInt.h>
25
26
26
27
namespace chip {
27
28
namespace Controller {
28
29
30
+ using namespace chip ::app::Clusters;
31
+
29
32
AutoCommissioner::AutoCommissioner ()
30
33
{
31
34
SetCommissioningParameters (CommissioningParameters ());
@@ -51,6 +54,12 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
51
54
mParams .SetFailsafeTimerSeconds (params.GetFailsafeTimerSeconds ().Value ());
52
55
}
53
56
57
+ if (params.GetCASEFailsafeTimerSeconds ().HasValue ())
58
+ {
59
+ ChipLogProgress (Controller, " Setting CASE failsafe timer from parameters" );
60
+ mParams .SetCASEFailsafeTimerSeconds (params.GetCASEFailsafeTimerSeconds ().Value ());
61
+ }
62
+
54
63
if (params.GetAdminSubject ().HasValue ())
55
64
{
56
65
ChipLogProgress (Controller, " Setting adminSubject from parameters" );
@@ -169,6 +178,27 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
169
178
return nextStage;
170
179
}
171
180
181
+ CommissioningStage AutoCommissioner::GetNextCommissioningStageNetworkSetup (CommissioningStage currentStage, CHIP_ERROR & lastErr)
182
+ {
183
+ if (mParams .GetWiFiCredentials ().HasValue () && mDeviceCommissioningInfo .network .wifi .endpoint != kInvalidEndpointId )
184
+ {
185
+ return CommissioningStage::kWiFiNetworkSetup ;
186
+ }
187
+ if (mParams .GetThreadOperationalDataset ().HasValue () && mDeviceCommissioningInfo .network .thread .endpoint != kInvalidEndpointId )
188
+ {
189
+ return CommissioningStage::kThreadNetworkSetup ;
190
+ }
191
+
192
+ ChipLogError (Controller, " Required network information not provided in commissioning parameters" );
193
+ ChipLogError (Controller, " Parameters supplied: wifi (%s) thread (%s)" , mParams .GetWiFiCredentials ().HasValue () ? " yes" : " no" ,
194
+ mParams .GetThreadOperationalDataset ().HasValue () ? " yes" : " no" );
195
+ ChipLogError (Controller, " Device supports: wifi (%s) thread(%s)" ,
196
+ mDeviceCommissioningInfo .network .wifi .endpoint == kInvalidEndpointId ? " no" : " yes" ,
197
+ mDeviceCommissioningInfo .network .thread .endpoint == kInvalidEndpointId ? " no" : " yes" );
198
+ lastErr = CHIP_ERROR_INVALID_ARGUMENT;
199
+ return CommissioningStage::kCleanup ;
200
+ }
201
+
172
202
CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal (CommissioningStage currentStage, CHIP_ERROR & lastErr)
173
203
{
174
204
if (mStopCommissioning )
@@ -194,27 +224,6 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
194
224
}
195
225
return CommissioningStage::kArmFailsafe ;
196
226
case CommissioningStage::kArmFailsafe :
197
- if (mNeedsNetworkSetup )
198
- {
199
- // if there is a WiFi or a Thread endpoint, then perform scan
200
- if ((mParams .GetAttemptWiFiNetworkScan ().ValueOr (false ) &&
201
- mDeviceCommissioningInfo .network .wifi .endpoint != kInvalidEndpointId ) ||
202
- (mParams .GetAttemptThreadNetworkScan ().ValueOr (false ) &&
203
- mDeviceCommissioningInfo .network .thread .endpoint != kInvalidEndpointId ))
204
- {
205
- return CommissioningStage::kScanNetworks ;
206
- }
207
- ChipLogProgress (Controller, " No NetworkScan enabled or WiFi/Thread endpoint not specified, skipping ScanNetworks" );
208
- }
209
- else
210
- {
211
- ChipLogProgress (Controller, " Not a BLE connection, skipping ScanNetworks" );
212
- }
213
- // skip scan step
214
- return CommissioningStage::kConfigRegulatory ;
215
- case CommissioningStage::kScanNetworks :
216
- return CommissioningStage::kNeedsNetworkCreds ;
217
- case CommissioningStage::kNeedsNetworkCreds :
218
227
return CommissioningStage::kConfigRegulatory ;
219
228
case CommissioningStage::kConfigRegulatory :
220
229
return CommissioningStage::kSendPAICertificateRequest ;
@@ -240,34 +249,30 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
240
249
// operational network because the provisioning of certificates will trigger the device to start operational advertising.
241
250
if (mNeedsNetworkSetup )
242
251
{
243
- if (mParams .GetWiFiCredentials ().HasValue () && mDeviceCommissioningInfo .network .wifi .endpoint != kInvalidEndpointId )
244
- {
245
- return CommissioningStage::kWiFiNetworkSetup ;
246
- }
247
- if (mParams .GetThreadOperationalDataset ().HasValue () &&
248
- mDeviceCommissioningInfo .network .thread .endpoint != kInvalidEndpointId )
252
+ // if there is a WiFi or a Thread endpoint, then perform scan
253
+ if (IsScanNeeded ())
249
254
{
250
- return CommissioningStage::kThreadNetworkSetup ;
255
+ // Perform Scan (kScanNetworks) and collect credentials (kNeedsNetworkCreds) right before configuring network.
256
+ // This order of steps allows the workflow to return to collect credentials again if network enablement fails.
257
+ return CommissioningStage::kScanNetworks ;
251
258
}
259
+ ChipLogProgress (Controller, " No NetworkScan enabled or WiFi/Thread endpoint not specified, skipping ScanNetworks" );
252
260
253
- ChipLogError (Controller, " Required network information not provided in commissioning parameters" );
254
- ChipLogError (Controller, " Parameters supplied: wifi (%s) thread (%s)" ,
255
- mParams .GetWiFiCredentials ().HasValue () ? " yes" : " no" ,
256
- mParams .GetThreadOperationalDataset ().HasValue () ? " yes" : " no" );
257
- ChipLogError (Controller, " Device supports: wifi (%s) thread(%s)" ,
258
- mDeviceCommissioningInfo .network .wifi .endpoint == kInvalidEndpointId ? " no" : " yes" ,
259
- mDeviceCommissioningInfo .network .thread .endpoint == kInvalidEndpointId ? " no" : " yes" );
260
- lastErr = CHIP_ERROR_INVALID_ARGUMENT;
261
- return CommissioningStage::kCleanup ;
261
+ return GetNextCommissioningStageNetworkSetup (currentStage, lastErr);
262
262
}
263
263
else
264
264
{
265
+ SetCASEFailsafeTimerIfNeeded ();
265
266
if (mParams .GetSkipCommissioningComplete ().ValueOr (false ))
266
267
{
267
268
return CommissioningStage::kCleanup ;
268
269
}
269
270
return CommissioningStage::kFindOperational ;
270
271
}
272
+ case CommissioningStage::kScanNetworks :
273
+ return CommissioningStage::kNeedsNetworkCreds ;
274
+ case CommissioningStage::kNeedsNetworkCreds :
275
+ return GetNextCommissioningStageNetworkSetup (currentStage, lastErr);
271
276
case CommissioningStage::kWiFiNetworkSetup :
272
277
if (mParams .GetThreadOperationalDataset ().HasValue () &&
273
278
mDeviceCommissioningInfo .network .thread .endpoint != kInvalidEndpointId )
@@ -296,13 +301,16 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
296
301
}
297
302
else if (mParams .GetSkipCommissioningComplete ().ValueOr (false ))
298
303
{
304
+ SetCASEFailsafeTimerIfNeeded ();
299
305
return CommissioningStage::kCleanup ;
300
306
}
301
307
else
302
308
{
309
+ SetCASEFailsafeTimerIfNeeded ();
303
310
return CommissioningStage::kFindOperational ;
304
311
}
305
312
case CommissioningStage::kThreadNetworkEnable :
313
+ SetCASEFailsafeTimerIfNeeded ();
306
314
if (mParams .GetSkipCommissioningComplete ().ValueOr (false ))
307
315
{
308
316
return CommissioningStage::kCleanup ;
@@ -321,6 +329,38 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
321
329
return CommissioningStage::kError ;
322
330
}
323
331
332
+ // No specific actions to take when an error happens since this command can fail and commissioning can still succeed.
333
+ static void OnFailsafeFailureForCASE (void * context, CHIP_ERROR error)
334
+ {
335
+ ChipLogProgress (Controller, " ExtendFailsafe received failure response %s\n " , chip::ErrorStr (error));
336
+ }
337
+
338
+ // No specific actions to take upon success.
339
+ static void
340
+ OnExtendFailsafeSuccessForCASE (void * context,
341
+ const app::Clusters::GeneralCommissioning::Commands::ArmFailSafeResponse::DecodableType & data)
342
+ {
343
+ ChipLogProgress (Controller, " ExtendFailsafe received ArmFailSafe response errorCode=%u" , to_underlying (data.errorCode ));
344
+ }
345
+
346
+ void AutoCommissioner::SetCASEFailsafeTimerIfNeeded ()
347
+ {
348
+ // if there is a final fail-safe timer configured then, send it
349
+ if (mParams .GetCASEFailsafeTimerSeconds ().HasValue () && mCommissioneeDeviceProxy != nullptr )
350
+ {
351
+ // send the command via the PASE session (mCommissioneeDeviceProxy) since the CASE portion of commissioning
352
+ // might be done by a different service (ex. PASE is done by a phone app and CASE is done by a Hub).
353
+ // Also, we want the CASE failsafe timer to apply for the time it takes the Hub to perform operational discovery,
354
+ // CASE establishment, and receipt of the commissioning complete command.
355
+ // We know that the mCommissioneeDeviceProxy is still valid at this point since it gets cleared during cleanup
356
+ // and SetCASEFailsafeTimerIfNeeded is always called before that stage.
357
+ mCommissioner ->ExtendArmFailSafe (mCommissioneeDeviceProxy , CommissioningStage::kFindOperational ,
358
+ mParams .GetCASEFailsafeTimerSeconds ().Value (),
359
+ GetCommandTimeout (mCommissioneeDeviceProxy , CommissioningStage::kArmFailsafe ),
360
+ OnExtendFailsafeSuccessForCASE, OnFailsafeFailureForCASE);
361
+ }
362
+ }
363
+
324
364
EndpointId AutoCommissioner::GetEndpoint (const CommissioningStage & stage) const
325
365
{
326
366
switch (stage)
@@ -481,8 +521,23 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
481
521
}
482
522
else if (report.Is <NetworkCommissioningStatusInfo>())
483
523
{
524
+ // This report type is used when an error happens in either NetworkConfig or ConnectNetwork commands
484
525
completionStatus.networkCommissioningStatus =
485
526
MakeOptional (report.Get <NetworkCommissioningStatusInfo>().networkCommissioningStatus );
527
+
528
+ // If we are configured to scan networks, then don't error out.
529
+ // Instead, allow the app to try another network.
530
+ if (IsScanNeeded ())
531
+ {
532
+ if (completionStatus.err == CHIP_NO_ERROR)
533
+ {
534
+ completionStatus.err = err;
535
+ }
536
+ err = CHIP_NO_ERROR;
537
+ // Walk back the completed stage to kScanNetworks.
538
+ // This will allow the app to try another network.
539
+ report.stageCompleted = CommissioningStage::kScanNetworks ;
540
+ }
486
541
}
487
542
}
488
543
else
0 commit comments