Skip to content

Commit 7608074

Browse files
committed
Auto-commissioner: support secondary network interface commissioning
1 parent 4239c88 commit 7608074

15 files changed

+230
-26
lines changed

examples/chip-tool/commands/pairing/Commands.h

+9
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,14 @@ class PairBleThread : public PairingCommand
165165
{}
166166
};
167167

168+
class PairBleWiFiOrThread : public PairingCommand
169+
{
170+
public:
171+
PairBleWiFiOrThread(CredentialIssuerCommands * credsIssuerConfig) :
172+
PairingCommand("ble-wifi-thread", PairingMode::Ble, PairingNetworkType::WiFiOrThread, credsIssuerConfig)
173+
{}
174+
};
175+
168176
class PairSoftAP : public PairingCommand
169177
{
170178
public:
@@ -233,6 +241,7 @@ void registerCommandsPairing(Commands & commands, CredentialIssuerCommands * cre
233241
make_unique<PairCodeThread>(credsIssuerConfig),
234242
make_unique<PairBleWiFi>(credsIssuerConfig),
235243
make_unique<PairBleThread>(credsIssuerConfig),
244+
make_unique<PairBleWiFiOrThread>(credsIssuerConfig),
236245
make_unique<PairSoftAP>(credsIssuerConfig),
237246
make_unique<PairAlreadyDiscovered>(credsIssuerConfig),
238247
make_unique<PairAlreadyDiscoveredByIndex>(credsIssuerConfig),

examples/chip-tool/commands/pairing/PairingCommand.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ CommissioningParameters PairingCommand::GetCommissioningParameters()
111111
case PairingNetworkType::Thread:
112112
params.SetThreadOperationalDataset(mOperationalDataset);
113113
break;
114+
case PairingNetworkType::WiFiOrThread:
115+
params.SetWiFiCredentials(Controller::WiFiCredentials(mSSID, mPassword));
116+
params.SetThreadOperationalDataset(mOperationalDataset);
117+
break;
114118
case PairingNetworkType::None:
115119
break;
116120
}

examples/chip-tool/commands/pairing/PairingCommand.h

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum class PairingNetworkType
4444
None,
4545
WiFi,
4646
Thread,
47+
WiFiOrThread,
4748
};
4849

4950
class PairingCommand : public CHIPCommand,
@@ -85,6 +86,11 @@ class PairingCommand : public CHIPCommand,
8586
case PairingNetworkType::Thread:
8687
AddArgument("operationalDataset", &mOperationalDataset);
8788
break;
89+
case PairingNetworkType::WiFiOrThread:
90+
AddArgument("ssid", &mSSID);
91+
AddArgument("password", &mPassword);
92+
AddArgument("operationalDataset", &mOperationalDataset);
93+
break;
8894
}
8995

9096
switch (mode)

src/controller/AutoCommissioner.cpp

+35-23
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,22 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag
298298

299299
CommissioningStage AutoCommissioner::GetNextCommissioningStageNetworkSetup(CommissioningStage currentStage, CHIP_ERROR & lastErr)
300300
{
301+
if (IsSecondaryNetworkSupported())
302+
{
303+
if (IsTriedSecondaryNetwork())
304+
{
305+
// Try secondary network interface.
306+
return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kThreadNetworkSetup
307+
: CommissioningStage::kWiFiNetworkSetup;
308+
}
309+
else
310+
{
311+
// Try primary network interface
312+
return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kWiFiNetworkSetup
313+
: CommissioningStage::kThreadNetworkSetup;
314+
}
315+
}
316+
301317
if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
302318
{
303319
return CommissioningStage::kWiFiNetworkSetup;
@@ -455,35 +471,15 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
455471
case CommissioningStage::kNeedsNetworkCreds:
456472
return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
457473
case CommissioningStage::kWiFiNetworkSetup:
458-
if (mParams.GetThreadOperationalDataset().HasValue() &&
459-
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
460-
{
461-
return CommissioningStage::kThreadNetworkSetup;
462-
}
463-
else
464-
{
465-
return CommissioningStage::kFailsafeBeforeWiFiEnable;
466-
}
474+
return CommissioningStage::kFailsafeBeforeWiFiEnable;
467475
case CommissioningStage::kThreadNetworkSetup:
468-
if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId)
469-
{
470-
return CommissioningStage::kFailsafeBeforeWiFiEnable;
471-
}
472-
else
473-
{
474-
return CommissioningStage::kFailsafeBeforeThreadEnable;
475-
}
476+
return CommissioningStage::kFailsafeBeforeThreadEnable;
476477
case CommissioningStage::kFailsafeBeforeWiFiEnable:
477478
return CommissioningStage::kWiFiNetworkEnable;
478479
case CommissioningStage::kFailsafeBeforeThreadEnable:
479480
return CommissioningStage::kThreadNetworkEnable;
480481
case CommissioningStage::kWiFiNetworkEnable:
481-
if (mParams.GetThreadOperationalDataset().HasValue() &&
482-
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)
483-
{
484-
return CommissioningStage::kThreadNetworkEnable;
485-
}
486-
else if (mParams.GetSkipCommissioningComplete().ValueOr(false))
482+
if (mParams.GetSkipCommissioningComplete().ValueOr(false))
487483
{
488484
SetCASEFailsafeTimerIfNeeded();
489485
return CommissioningStage::kCleanup;
@@ -502,6 +498,10 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
502498
return CommissioningStage::kEvictPreviousCaseSessions;
503499
case CommissioningStage::kEvictPreviousCaseSessions:
504500
return CommissioningStage::kFindOperationalForStayActive;
501+
case CommissioningStage::kPrimaryOperationalNetworkFailed:
502+
return CommissioningStage::kDisablePrimaryNetworkInterface;
503+
case CommissioningStage::kDisablePrimaryNetworkInterface:
504+
return GetNextCommissioningStageNetworkSetup(currentStage, lastErr);
505505
case CommissioningStage::kFindOperationalForStayActive:
506506
return CommissioningStage::kICDSendStayActive;
507507
case CommissioningStage::kICDSendStayActive:
@@ -564,6 +564,8 @@ EndpointId AutoCommissioner::GetEndpoint(const CommissioningStage & stage) const
564564
case CommissioningStage::kThreadNetworkSetup:
565565
case CommissioningStage::kThreadNetworkEnable:
566566
return mDeviceCommissioningInfo.network.thread.endpoint;
567+
case CommissioningStage::kDisablePrimaryNetworkInterface:
568+
return kRootEndpointId;
567569
default:
568570
return kRootEndpointId;
569571
}
@@ -729,6 +731,16 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
729731
report.stageCompleted = CommissioningStage::kScanNetworks;
730732
}
731733
}
734+
735+
if (err != CHIP_NO_ERROR && IsSecondaryNetworkSupported() && !IsTriedSecondaryNetwork() &&
736+
completionStatus.failedStage.HasValue() && completionStatus.failedStage.Value() >= kWiFiNetworkSetup &&
737+
completionStatus.failedStage.Value() <= kICDSendStayActive)
738+
{
739+
// Primary network failed, disable primary network interface and try secondary network interface.
740+
SetTrySecondaryNetwork();
741+
err = CHIP_NO_ERROR;
742+
report.stageCompleted = CommissioningStage::kPrimaryOperationalNetworkFailed;
743+
}
732744
}
733745
else
734746
{

src/controller/AutoCommissioner.h

+15
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ class AutoCommissioner : public CommissioningDelegate
9494
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId));
9595
};
9696

97+
// Helper function to Determine whether secondary network interface is supported.
98+
// Only true if information is provided for both networks, and the target has endpoint
99+
// for wifi and thread.
100+
bool IsSecondaryNetworkSupported() const
101+
{
102+
return ((mParams.GetSupportsConcurrentConnection().ValueOr(false) && mParams.GetWiFiCredentials().HasValue() &&
103+
mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId) &&
104+
mParams.GetThreadOperationalDataset().HasValue() &&
105+
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId);
106+
}
107+
108+
void SetTrySecondaryNetwork() { mAttemptedSecondaryNetwork = true; }
109+
bool IsTriedSecondaryNetwork() const { return mAttemptedSecondaryNetwork; }
110+
bool mAttemptedSecondaryNetwork = false;
111+
97112
bool mStopCommissioning = false;
98113

99114
DeviceCommissioner * mCommissioner = nullptr;

src/controller/CHIPDeviceController.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <app/server/Dnssd.h>
3737
#include <controller/CurrentFabricRemover.h>
3838
#include <controller/InvokeInteraction.h>
39+
#include <controller/WriteInteraction.h>
3940
#include <credentials/CHIPCert.h>
4041
#include <credentials/DeviceAttestationCredsProvider.h>
4142
#include <crypto/CHIPCryptoPAL.h>
@@ -1801,6 +1802,12 @@ void DeviceCommissioner::OnBasicSuccess(void * context, const chip::app::DataMod
18011802
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
18021803
}
18031804

1805+
void DeviceCommissioner::OnInterfaceEnableWriteSuccessResponse(void * context)
1806+
{
1807+
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
1808+
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
1809+
}
1810+
18041811
void DeviceCommissioner::OnBasicFailure(void * context, CHIP_ERROR error)
18051812
{
18061813
ChipLogProgress(Controller, "Received failure response %s\n", chip::ErrorStr(error));
@@ -2740,6 +2747,18 @@ DeviceCommissioner::SendCommissioningCommand(DeviceProxy * device, const Request
27402747
onFailureCb, NullOptional, timeout, (!fireAndForget) ? &mInvokeCancelFn : nullptr);
27412748
}
27422749

2750+
template <typename AttrType>
2751+
CHIP_ERROR DeviceCommissioner::SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster,
2752+
AttributeId attribute, const AttrType & requestData,
2753+
WriteResponseSuccessCallback successCb,
2754+
WriteResponseFailureCallback failureCb)
2755+
{
2756+
auto onSuccessCb = [this, successCb](const app::ConcreteAttributePath & aPath) { successCb(this); };
2757+
auto onFailureCb = [this, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) { failureCb(this, aError); };
2758+
return WriteAttribute(device->GetSecureSession().Value(), endpoint, cluster, attribute, requestData, onSuccessCb, onFailureCb,
2759+
NullOptional, nullptr, NullOptional);
2760+
}
2761+
27432762
void DeviceCommissioner::SendCommissioningReadRequest(DeviceProxy * proxy, Optional<System::Clock::Timeout> timeout,
27442763
app::AttributePathParams * readPaths, size_t readPathsSize)
27452764
{
@@ -3424,6 +3443,26 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
34243443
);
34253444
}
34263445
break;
3446+
case CommissioningStage::kPrimaryOperationalNetworkFailed: {
3447+
// nothing to do. This stage indicates that the primary operation network failed and the network interface should be
3448+
// disabled later.
3449+
break;
3450+
}
3451+
case CommissioningStage::kDisablePrimaryNetworkInterface: {
3452+
NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::Type request = false;
3453+
CHIP_ERROR err = SendCommissioningWriteRequest(
3454+
proxy, endpoint, NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::GetClusterId(),
3455+
NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::GetAttributeId(), request,
3456+
OnInterfaceEnableWriteSuccessResponse, OnBasicFailure);
3457+
if (err != CHIP_NO_ERROR)
3458+
{
3459+
// We won't get any async callbacks here, so just complete our stage.
3460+
ChipLogError(Controller, "Failed to send InterfaceEnabled write request: %" CHIP_ERROR_FORMAT, err.Format());
3461+
CommissioningStageComplete(err);
3462+
return;
3463+
}
3464+
break;
3465+
}
34273466
case CommissioningStage::kICDSendStayActive: {
34283467
if (!(params.GetICDStayActiveDurationMsec().HasValue()))
34293468
{

src/controller/CHIPDeviceController.h

+6
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,8 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
965965
OnICDManagementStayActiveResponse(void * context,
966966
const app::Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType & data);
967967

968+
static void OnInterfaceEnableWriteSuccessResponse(void * context);
969+
968970
/**
969971
* @brief
970972
* This function processes the CSR sent by the device.
@@ -1025,6 +1027,10 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
10251027
Optional<System::Clock::Timeout> timeout = NullOptional, bool fireAndForget = false);
10261028
void SendCommissioningReadRequest(DeviceProxy * proxy, Optional<System::Clock::Timeout> timeout,
10271029
app::AttributePathParams * readPaths, size_t readPathsSize);
1030+
template <typename AttrType>
1031+
CHIP_ERROR SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster, AttributeId attribute,
1032+
const AttrType & requestData, WriteResponseSuccessCallback successCb,
1033+
WriteResponseFailureCallback failureCb);
10281034
void CancelCommissioningInteractions();
10291035
void CancelCASECallbacks();
10301036

src/controller/CommissioningDelegate.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ const char * StageToString(CommissioningStage stage)
136136
case kNeedsNetworkCreds:
137137
return "NeedsNetworkCreds";
138138

139+
case kPrimaryOperationalNetworkFailed:
140+
return "kPrimaryOperationalNetworkFailed";
141+
142+
case kDisablePrimaryNetworkInterface:
143+
return "kDisablePrimaryNetworkInterface";
144+
139145
default:
140146
return "???";
141147
}

src/controller/CommissioningDelegate.h

+3
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ enum CommissioningStage : uint8_t
7979
/// Call CHIPDeviceController::NetworkCredentialsReady() when CommissioningParameters is populated with
8080
/// network credentials to use in kWiFiNetworkSetup or kThreadNetworkSetup steps.
8181
kNeedsNetworkCreds,
82+
kPrimaryOperationalNetworkFailed, ///< Indicate that the primary operational network (on root endpoint) failed, should disable
83+
///< the primary network interface later.
84+
kDisablePrimaryNetworkInterface, ///< Send InterfaceEnabled write request to the device to disable network interface.
8285
};
8386

8487
enum class ICDRegistrationStrategy : uint8_t

src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,10 @@ CHIP_ERROR ConnectivityManagerImpl::InitWiFi()
391391
mWiFiStationMode = kWiFiStationMode_Disabled;
392392
mWiFiStationState = kWiFiStationState_NotConnected;
393393
mWiFiStationReconnectInterval = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL);
394+
if (!NetworkCommissioning::ESPWiFiDriver::GetInstance().GetEnabled())
395+
{
396+
mWiFiStationMode = kWiFiStationMode_ApplicationControlled;
397+
}
394398

395399
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP
396400
mLastAPDemandTime = System::Clock::kZero;

src/platform/ESP32/NetworkCommissioningDriver.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ CHIP_ERROR ESPWiFiDriver::CommitConfiguration()
147147
CHIP_ERROR ESPWiFiDriver::RevertConfiguration()
148148
{
149149
mStagingNetwork = mSavedNetwork;
150+
if (!GetEnabled())
151+
{
152+
// When reverting, set InterfaceEnabled to default value (true).
153+
ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Delete(kInterfaceEnabled));
154+
}
150155
return CHIP_NO_ERROR;
151156
}
152157

@@ -196,6 +201,12 @@ Status ESPWiFiDriver::ReorderNetwork(ByteSpan networkId, uint8_t index, MutableC
196201

197202
CHIP_ERROR ESPWiFiDriver::ConnectWiFiNetwork(const char * ssid, uint8_t ssidLen, const char * key, uint8_t keyLen)
198203
{
204+
if (!GetEnabled())
205+
{
206+
// Set InterfaceEnabled to default value (true).
207+
ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Delete(kInterfaceEnabled));
208+
}
209+
199210
// If device is already connected to WiFi, then disconnect the WiFi,
200211
// clear the WiFi configurations and add the newly provided WiFi configurations.
201212
if (chip::DeviceLayer::Internal::ESP32Utils::IsStationProvisioned())
@@ -307,6 +318,44 @@ void ESPWiFiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callbac
307318
}
308319
}
309320

321+
CHIP_ERROR ESPWiFiDriver::SetEnabled(bool enabled)
322+
{
323+
if (enabled == GetEnabled())
324+
{
325+
return CHIP_NO_ERROR;
326+
}
327+
328+
ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kInterfaceEnabled, &enabled, sizeof(enabled)));
329+
330+
if (!enabled)
331+
{
332+
if (chip::DeviceLayer::Internal::ESP32Utils::IsStationProvisioned())
333+
{
334+
ChipLogProgress(DeviceLayer, "Disconnecting WiFi station interface");
335+
esp_err_t err = esp_wifi_disconnect();
336+
if (err != ESP_OK)
337+
{
338+
ChipLogError(DeviceLayer, "esp_wifi_disconnect() failed: %s", esp_err_to_name(err));
339+
return chip::DeviceLayer::Internal::ESP32Utils::MapError(err);
340+
}
341+
return ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_ApplicationControlled);
342+
}
343+
}
344+
else
345+
{
346+
ReturnErrorOnFailure(ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled));
347+
}
348+
return CHIP_NO_ERROR;
349+
}
350+
351+
bool ESPWiFiDriver::GetEnabled()
352+
{
353+
bool value;
354+
// InterfaceEnabled default value is true.
355+
VerifyOrReturnValue(PersistedStorage::KeyValueStoreMgr().Get(kInterfaceEnabled, &value, sizeof(value)) == CHIP_NO_ERROR, true);
356+
return value;
357+
}
358+
310359
CHIP_ERROR ESPWiFiDriver::StartScanWiFiNetworks(ByteSpan ssid)
311360
{
312361
esp_err_t err = ESP_OK;

src/platform/ESP32/NetworkCommissioningDriver.h

+3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class ESPWiFiDriver final : public WiFiDriver
9494
// BaseDriver
9595
NetworkIterator * GetNetworks() override { return new WiFiNetworkIterator(this); }
9696
CHIP_ERROR Init(NetworkStatusChangeCallback * networkStatusChangeCallback) override;
97+
CHIP_ERROR SetEnabled(bool enabled) override;
98+
bool GetEnabled() override;
9799
void Shutdown() override;
98100

99101
// WirelessDriver
@@ -131,6 +133,7 @@ class ESPWiFiDriver final : public WiFiDriver
131133
}
132134

133135
private:
136+
static constexpr const char * kInterfaceEnabled = "g/esp/en";
134137
bool NetworkMatch(const WiFiNetwork & network, ByteSpan networkId);
135138
CHIP_ERROR StartScanWiFiNetworks(ByteSpan ssid);
136139

0 commit comments

Comments
 (0)