Skip to content

Commit

Permalink
Add Terms and Conditions (T&C) Feature Support for Commissioning (#36863
Browse files Browse the repository at this point in the history
)

* Add Terms and Conditions (T&C) Feature Support for Commissioning

This commit introduces comprehensive support for handling Terms and
Conditions (T&C) during the commissioning process, enhancing
compatibility with Matter device certification requirements.

Key changes include:

1. **Commissioning Process Updates**:
   - Introduced `SetRequireTermsAndConditionsAcknowledgement`,
     `SetTermsAcknowledgements`, and `SetSkipCommissioningComplete` APIs
     in the commissioning library.
   - Updated commissioning stages to include `kGetTCAcknowledgments` and
     `kConfigureTCAcknowledgments` for seamless integration of T&C
     acknowledgements.
   - Added methods for processing T&C acknowledgements and advancing
     commissioning stages upon user response.

2. **Test Framework Enhancements**:
   - Added arguments (`tc_version`, `tc_user_response`,
     `in_test_commissioning_method`) for specifying T&C configuration in
     tests.
   - Enhanced `populate_commissioning_args` to manage new T&C-related
     arguments.
   - Updated Python test bindings and Matter test infrastructure to
     support T&C workflows.

3. **Chip-Tool Improvements**:
   - Extended `PairingCommand` to handle T&C-related arguments
     (`require-tc-acknowledgements`, `tc-acknowledgements`,
     `tc-acknowledgements-version`) for test scenarios.
   - Ensured backward compatibility by defaulting new parameters to
     preserve pre-1.4 behavior.

* Removed the "wait for terms and conditions stage"

The wait-stage is not required. The user input availability must be a
pre-condition for starting the AutoCommissioner process. The wait stage
was previously to support requesting user input after identifying the
device VID/PID using a different channel than within the pairing
payload.

* [doc] Improve Terms and Conditions commissioning arguments documentation

Updated documentation for T&C-related commissioning arguments to better
reflect their actual usage and purpose:

- require-tc-acknowledgements: Clarified the impact on commissioning flow
- tc-acknowledgements: Explained the bit-field usage for user acceptance
- tc-acknowledgements-version: Added context about version tracking

* [controller] Remove T&C acknowledgements from external buffer clearing

The Terms and Conditions acknowledgements parameter was incorrectly included
in ClearExternalBufferDependentValues(). This parameter contains a fixed-size
struct with two uint16_t values and does not reference any external buffers.

The CommissioningParameters class appears to be designed for additive-only
parameter setting without explicit clear/reset functionality, so removing
this inappropriate clearing operation is the correct approach.

* [controller] Fix CommissioningStage enum order for T&C acknowledgements

Move kConfigureTCAcknowledgments before kCleanup in the CommissioningStage
enum to fix cirque test failures. The tests validate that commissioning stages
do not exceed kCleanup, which was causing failures when T&C acknowledgements
were positioned after it.

While the original comment from 2 years ago suggested the enum order was
fixed, testing reveals that the stages can be reordered. The cirque tests
now pass with this corrected ordering, indicating that any previous
constraints on enum ordering no longer apply.

* [doc] Clarify required arguments for T&C acknowledgements

Update help text for require-tc-acknowledgements to explicitly state which
arguments must be provided when T&C acknowledgements are required. Instead
of the vague "valid T&C acknowledgements", now specifically mentions that
both tc-acknowledgements and tc-acknowledgements-version arguments are
mandatory for successful commissioning when this option is enabled.

* Update src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py

Co-authored-by: Tennessee Carmel-Veilleux <[email protected]>

* Restyle

* Renamed variable

---------

Co-authored-by: Tennessee Carmel-Veilleux <[email protected]>
  • Loading branch information
swan-amazon and tcarmelveilleux authored Dec 21, 2024
1 parent 4c725be commit af336ec
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 20 deletions.
16 changes: 15 additions & 1 deletion examples/chip-tool/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -129,6 +129,20 @@ CommissioningParameters PairingCommand::GetCommissioningParameters()
params.SetCountryCode(CharSpan::fromCharString(mCountryCode.Value()));
}

// Default requiring TCs to false, to preserve release 1.3 chip-tool behavior
params.SetRequireTermsAndConditionsAcknowledgement(mRequireTCAcknowledgements.ValueOr(false));

// mTCAcknowledgements and mTCAcknowledgementVersion are optional, but related. When one is missing, default the value to 0, to
// increase the test tools ability to test the applications.
if (mTCAcknowledgements.HasValue() || mTCAcknowledgementVersion.HasValue())
{
TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = {
.acceptedTermsAndConditions = mTCAcknowledgements.ValueOr(0),
.acceptedTermsAndConditionsVersion = mTCAcknowledgementVersion.ValueOr(0),
};
params.SetTermsAndConditionsAcknowledgement(termsAndConditionsAcknowledgement);
}

// mTimeZoneList is an optional argument managed by TypedComplexArgument mComplex_TimeZones.
// Since optional Complex arguments are not currently supported via the <chip::Optional> class,
// we will use mTimeZoneList.data() value to determine if the argument was provided.
Expand Down
18 changes: 17 additions & 1 deletion examples/chip-tool/commands/pairing/PairingCommand.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -202,6 +202,19 @@ class PairingCommand : public CHIPCommand,
AddArgument("dst-offset", &mComplex_DSTOffsets,
"DSTOffset list to use when setting Time Synchronization cluster's DSTOffset attribute",
Argument::kOptional);

AddArgument("require-tc-acknowledgements", 0, 1, &mRequireTCAcknowledgements,
"Indicates whether Terms and Conditions acknowledgements are required during commissioning. If set to "
"true, the tc-acknowledgements and tc-acknowledgements-version arguments must be provided for the "
"commissioning to succeed. If false, the T&C acknowledgement step will be skipped.");

AddArgument("tc-acknowledgements", 0, UINT16_MAX, &mTCAcknowledgements,
"Bit-field value indicating which Terms and Conditions have been accepted by the user. This value is sent "
"to the device during commissioning via the General Commissioning cluster");

AddArgument("tc-acknowledgements-version", 0, UINT16_MAX, &mTCAcknowledgementVersion,
"Version number of the Terms and Conditions that were accepted by the user. This value is sent to the "
"device during commissioning to indicate which T&C version was acknowledged");
}

AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
Expand Down Expand Up @@ -259,6 +272,9 @@ class PairingCommand : public CHIPCommand,
chip::Optional<uint64_t> mICDMonitoredSubject;
chip::Optional<chip::app::Clusters::IcdManagement::ClientTypeEnum> mICDClientType;
chip::Optional<uint32_t> mICDStayActiveDurationMsec;
chip::Optional<bool> mRequireTCAcknowledgements;
chip::Optional<uint16_t> mTCAcknowledgements;
chip::Optional<uint16_t> mTCAcknowledgementVersion;
chip::app::DataModel::List<chip::app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> mTimeZoneList;
TypedComplexArgument<chip::app::DataModel::List<chip::app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>>
mComplex_TimeZones;
Expand Down
4 changes: 3 additions & 1 deletion src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -310,6 +310,8 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
case CommissioningStage::kArmFailsafe:
return CommissioningStage::kConfigRegulatory;
case CommissioningStage::kConfigRegulatory:
return CommissioningStage::kConfigureTCAcknowledgments;
case CommissioningStage::kConfigureTCAcknowledgments:
if (mDeviceCommissioningInfo.requiresUTC)
{
return CommissioningStage::kConfigureUTCTime;
Expand Down
51 changes: 50 additions & 1 deletion src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -2795,6 +2795,22 @@ void DeviceCommissioner::OnSetRegulatoryConfigResponse(
commissioner->CommissioningStageComplete(err, report);
}

void DeviceCommissioner::OnSetTCAcknowledgementsResponse(
void * context, const GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data)
{
CommissioningDelegate::CommissioningReport report;
CHIP_ERROR err = CHIP_NO_ERROR;

ChipLogProgress(Controller, "Received SetTCAcknowledgements response errorCode=%u", to_underlying(data.errorCode));
if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
{
err = CHIP_ERROR_INTERNAL;
report.Set<CommissioningErrorInfo>(data.errorCode);
}
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
commissioner->CommissioningStageComplete(err, report);
}

void DeviceCommissioner::OnSetTimeZoneResponse(void * context,
const TimeSynchronization::Commands::SetTimeZoneResponse::DecodableType & data)
{
Expand Down Expand Up @@ -3207,6 +3223,39 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
}
}
break;
case CommissioningStage::kConfigureTCAcknowledgments: {
ChipLogProgress(Controller, "Setting Terms and Conditions");

if (!params.GetRequireTermsAndConditionsAcknowledgement())
{
ChipLogProgress(Controller, "Setting Terms and Conditions: Skipped");
CommissioningStageComplete(CHIP_NO_ERROR);
return;
}

if (!params.GetTermsAndConditionsAcknowledgement().HasValue())
{
ChipLogError(Controller, "No acknowledgements provided");
CommissioningStageComplete(CHIP_ERROR_INCORRECT_STATE);
return;
}

GeneralCommissioning::Commands::SetTCAcknowledgements::Type request;
TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = params.GetTermsAndConditionsAcknowledgement().Value();
request.TCUserResponse = termsAndConditionsAcknowledgement.acceptedTermsAndConditions;
request.TCVersion = termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion;

ChipLogProgress(Controller, "Setting Terms and Conditions: %hu, %hu", request.TCUserResponse, request.TCVersion);
CHIP_ERROR err =
SendCommissioningCommand(proxy, request, OnSetTCAcknowledgementsResponse, OnBasicFailure, endpoint, timeout);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to send SetTCAcknowledgements command: %" CHIP_ERROR_FORMAT, err.Format());
CommissioningStageComplete(err);
return;
}
break;
}
case CommissioningStage::kSendPAICertificateRequest: {
ChipLogProgress(Controller, "Sending request for PAI certificate");
CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kPAI, timeout);
Expand Down
5 changes: 4 additions & 1 deletion src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -960,6 +960,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
static void OnSetRegulatoryConfigResponse(
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data);
static void OnSetTCAcknowledgementsResponse(
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data);
static void OnSetUTCError(void * context, CHIP_ERROR error);
static void
OnSetTimeZoneResponse(void * context,
Expand Down
3 changes: 3 additions & 0 deletions src/controller/CommissioningDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const char * StageToString(CommissioningStage stage)
case kConfigRegulatory:
return "ConfigRegulatory";

case kConfigureTCAcknowledgments:
return "ConfigureTCAcknowledgments";

case kConfigureUTCTime:
return "ConfigureUTCTime";

Expand Down
36 changes: 32 additions & 4 deletions src/controller/CommissioningDelegate.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -69,10 +69,8 @@ enum CommissioningStage : uint8_t
///< Commissioning Complete command
kSendComplete, ///< Send CommissioningComplete (0x30:4) command to the device
kICDSendStayActive, ///< Send Keep Alive to ICD
kCleanup, ///< Call delegates with status, free memory, clear timers and state
/// Send ScanNetworks (0x31:0) command to the device.
/// ScanNetworks can happen anytime after kArmFailsafe.
/// However, the cirque tests fail if it is earlier in the list
kScanNetworks,
/// Waiting for the higher layer to provide network credentials before continuing the workflow.
/// Call CHIPDeviceController::NetworkCredentialsReady() when CommissioningParameters is populated with
Expand All @@ -81,7 +79,9 @@ enum CommissioningStage : uint8_t
kPrimaryOperationalNetworkFailed, ///< Indicate that the primary operational network (on root endpoint) failed, should remove
///< the primary network config later.
kRemoveWiFiNetworkConfig, ///< Remove Wi-Fi network config.
kRemoveThreadNetworkConfig ///< Remove Thread network config.
kRemoveThreadNetworkConfig, ///< Remove Thread network config.
kConfigureTCAcknowledgments, ///< Send SetTCAcknowledgements (0x30:6) command to the device
kCleanup, ///< Call delegates with status, free memory, clear timers and state
};

enum class ICDRegistrationStrategy : uint8_t
Expand All @@ -104,6 +104,12 @@ struct WiFiCredentials
WiFiCredentials(ByteSpan newSsid, ByteSpan newCreds) : ssid(newSsid), credentials(newCreds) {}
};

struct TermsAndConditionsAcknowledgement
{
uint16_t acceptedTermsAndConditions;
uint16_t acceptedTermsAndConditionsVersion;
};

struct NOCChainGenerationParameters
{
ByteSpan nocsrElements;
Expand Down Expand Up @@ -168,6 +174,13 @@ class CommissioningParameters
// The country code to be used for the node, if set.
Optional<CharSpan> GetCountryCode() const { return mCountryCode; }

bool GetRequireTermsAndConditionsAcknowledgement() const { return mRequireTermsAndConditionsAcknowledgement; }

Optional<TermsAndConditionsAcknowledgement> GetTermsAndConditionsAcknowledgement() const
{
return mTermsAndConditionsAcknowledgement;
}

// Time zone to set for the node
// If required, this will be truncated to fit the max size allowable on the node
Optional<app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>> GetTimeZone() const
Expand Down Expand Up @@ -340,6 +353,19 @@ class CommissioningParameters
return *this;
}

CommissioningParameters & SetRequireTermsAndConditionsAcknowledgement(bool requireTermsAndConditionsAcknowledgement)
{
mRequireTermsAndConditionsAcknowledgement = requireTermsAndConditionsAcknowledgement;
return *this;
}

CommissioningParameters &
SetTermsAndConditionsAcknowledgement(TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement)
{
mTermsAndConditionsAcknowledgement.SetValue(termsAndConditionsAcknowledgement);
return *this;
}

// The lifetime of the list buffer needs to exceed the lifetime of the CommissioningParameters object.
CommissioningParameters &
SetTimeZone(app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> timeZone)
Expand Down Expand Up @@ -611,6 +637,7 @@ class CommissioningParameters
Optional<ByteSpan> mAttestationNonce;
Optional<WiFiCredentials> mWiFiCreds;
Optional<CharSpan> mCountryCode;
Optional<TermsAndConditionsAcknowledgement> mTermsAndConditionsAcknowledgement;
Optional<ByteSpan> mThreadOperationalDataset;
Optional<NOCChainGenerationParameters> mNOCChainGenerationParameters;
Optional<ByteSpan> mRootCert;
Expand Down Expand Up @@ -643,6 +670,7 @@ class CommissioningParameters
Optional<uint32_t> mICDStayActiveDurationMsec;
ICDRegistrationStrategy mICDRegistrationStrategy = ICDRegistrationStrategy::kIgnore;
bool mCheckForMatchingFabric = false;
bool mRequireTermsAndConditionsAcknowledgement = false;
};

struct RequestedCertificate
Expand Down
25 changes: 25 additions & 0 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ PyChipError pychip_DeviceController_OpenCommissioningWindow(chip::Controller::De
bool pychip_DeviceController_GetIPForDiscoveredDevice(chip::Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr,
uint32_t len);

PyChipError pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement(bool tcRequired);

PyChipError pychip_DeviceController_SetTermsAcknowledgements(uint16_t tcVersion, uint16_t tcUserResponse);

PyChipError pychip_DeviceController_SetSkipCommissioningComplete(bool skipCommissioningComplete);

// Pairing Delegate
PyChipError
pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::ScriptDevicePairingDelegate * pairingDelegate,
Expand Down Expand Up @@ -572,6 +578,25 @@ PyChipError pychip_DeviceController_SetDefaultNtp(const char * defaultNTP)
return ToPyChipError(CHIP_NO_ERROR);
}

PyChipError pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement(bool tcRequired)
{
sCommissioningParameters.SetRequireTermsAndConditionsAcknowledgement(tcRequired);
return ToPyChipError(CHIP_NO_ERROR);
}

PyChipError pychip_DeviceController_SetTermsAcknowledgements(uint16_t tcVersion, uint16_t tcUserResponse)
{
sCommissioningParameters.SetTermsAndConditionsAcknowledgement(
{ .acceptedTermsAndConditions = tcUserResponse, .acceptedTermsAndConditionsVersion = tcVersion });
return ToPyChipError(CHIP_NO_ERROR);
}

PyChipError pychip_DeviceController_SetSkipCommissioningComplete(bool skipCommissioningComplete)
{
sCommissioningParameters.SetSkipCommissioningComplete(skipCommissioningComplete);
return ToPyChipError(CHIP_NO_ERROR);
}

PyChipError pychip_DeviceController_SetTrustedTimeSource(chip::NodeId nodeId, chip::EndpointId endpoint)
{
chip::app::Clusters::TimeSynchronization::Structs::FabricScopedTrustedTimeSourceStruct::Type timeSource = { .nodeID = nodeId,
Expand Down
30 changes: 30 additions & 0 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2005,6 +2005,15 @@ def _InitLib(self):
self._dmLib.pychip_CreateManualCode.restype = PyChipError
self._dmLib.pychip_CreateManualCode.argtypes = [c_uint16, c_uint32, c_char_p, c_size_t, POINTER(c_size_t)]

self._dmLib.pychip_DeviceController_SetSkipCommissioningComplete.restype = PyChipError
self._dmLib.pychip_DeviceController_SetSkipCommissioningComplete.argtypes = [c_bool]

self._dmLib.pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement.restype = PyChipError
self._dmLib.pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement.argtypes = [c_bool]

self._dmLib.pychip_DeviceController_SetTermsAcknowledgements.restype = PyChipError
self._dmLib.pychip_DeviceController_SetTermsAcknowledgements.argtypes = [c_uint16, c_uint16]


class ChipDeviceController(ChipDeviceControllerBase):
''' The ChipDeviceCommissioner binding, named as ChipDeviceController
Expand Down Expand Up @@ -2133,6 +2142,27 @@ def SetDSTOffset(self, offset: int, validStarting: int, validUntil: int):
lambda: self._dmLib.pychip_DeviceController_SetDSTOffset(offset, validStarting, validUntil)
).raise_on_error()

def SetTCRequired(self, tcRequired: bool):
''' Set whether TC Acknowledgements should be set during commissioning'''
self.CheckIsActive()
self._ChipStack.Call(
lambda: self._dmLib.pychip_DeviceController_SetRequireTermsAndConditionsAcknowledgement(tcRequired)
).raise_on_error()

def SetTCAcknowledgements(self, tcAcceptedVersion: int, tcUserResponse: int):
''' Set the TC acknowledgements to set during commissioning'''
self.CheckIsActive()
self._ChipStack.Call(
lambda: self._dmLib.pychip_DeviceController_SetTermsAcknowledgements(tcAcceptedVersion, tcUserResponse)
).raise_on_error()

def SetSkipCommissioningComplete(self, skipCommissioningComplete: bool):
''' Set whether to skip the commissioning complete callback'''
self.CheckIsActive()
self._ChipStack.Call(
lambda: self._dmLib.pychip_DeviceController_SetSkipCommissioningComplete(skipCommissioningComplete)
).raise_on_error()

def SetDefaultNTP(self, defaultNTP: str):
''' Set the DefaultNTP to set during commissioning'''
self.CheckIsActive()
Expand Down
7 changes: 7 additions & 0 deletions src/controller/python/chip/commissioning/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ class WiFiCredentials:
passphrase: bytes


@dataclasses.dataclass
class TermsAndConditionsParameters:
version: int
user_response: int


@dataclasses.dataclass
class Parameters:
pase_param: Union[PaseOverBLEParameters, PaseOverIPParameters]
Expand All @@ -80,6 +86,7 @@ class Parameters:
commissionee_info: CommissioneeInfo
wifi_credentials: WiFiCredentials
thread_credentials: bytes
tc_acknowledgements: Optional[TermsAndConditionsParameters] = None
failsafe_expiry_length_seconds: int = 600


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ async def send_regulatory_config(self, parameter: commissioning.Parameters, node
if response.errorCode != 0:
raise commissioning.CommissionFailure(repr(response))

async def send_terms_and_conditions_acknowledgements(self, parameter: commissioning.Parameters, node_id: int):
self._logger.info("Settings Terms and Conditions")
if parameter.tc_acknowledgements:
response = await self._devCtrl.SendCommand(node_id, commissioning.ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements(
TCVersion=parameter.tc_acknowledgements.version, TCUserResponse=parameter.tc_acknowledgements.user_response
))
if response.errorCode != 0:
raise commissioning.CommissionFailure(repr(response))

async def complete_commission(self, node_id: int):
response = await self._devCtrl.SendCommand(node_id, commissioning.ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Commands.CommissioningComplete())
if response.errorCode != 0:
Expand Down
Loading

0 comments on commit af336ec

Please sign in to comment.