Matter Device Pairing

Last Updated on : 2024-08-22 02:42:07download

Matter device pairing applies to both the Tuya-enabled and third-party Matter devices. The API calls for both types of devices remain consistent, but their pairing behavior differs. Matter device pairing supports auto-discovery, QR code scan, and manual setup code.

The ThingSmartBusinessExtensionKitMatterExtra component offers more features than the ThingSmartMatterActivator. If you are still using ThingSmartMatterActivator, please refer to this document.

Before the integration of a Matter device into your project, you must configure the project. For the pairing process implemented by Tuya, Matter devices are classified into Tuya-enabled Matter devices and third-party Matter devices. For a third-party Matter device, add an extension target to your Xcode project.

Prerequisites

Configure and integrate with main project

Configure entitlements

  1. Open the project settings in Xcode.

  2. Choose the target of the main project > Signing & Capabilities, and click + Capability.

    Matter Device Pairing
  3. Add the entitlement Matter Allow Setup Payload that is used to handle parsing of Matter QR codes.

  4. Add the App Groups entitlement that is used to share data with Matter Extension Target. Set App Group ID to the same value as Matter Extension Target.

  5. Add the Background Modes entitlement and select Uses Bluetooth LE accessories that is used to ensure stable communication over Bluetooth.

    The following figure shows these steps.

    Matter Device Pairing

Configure Info.plist

  1. Open the project settings in Xcode.

  2. Choose the target of the main project > Info > Custom iOS Target Properties.

    Matter Device Pairing
    • Privacy - Bluetooth Peripheral Usage Description

      Add the entitlement NSBluetoothPeripheralUsageDescription that is used for privacy and permission purposes and to provide a user-facing description of the reason for requesting access to Bluetooth peripherals.

    • Bonjour services

      Matter has a strong dependency on communication on a LAN. In light of this, you must configure Bonjour services in the file Info.plist of the main project. Example:

      <key>NSBonjourServices</key>
          <array>
              <string>_meshcop._udp</string>
              <string>_matter._tcp</string>
              <string>_matterc._udp</string>
              <string>_matterd._udp</string>
          </array>
      

Use CocoaPods for fast integration

  1. We recommend that you update CocoaPods to the latest version.

  2. Add the following code block to the Podfile:

    platform :ios, '9.0'
    
    target 'Your_Project_Name' do
        pod "ThingSmartMatterKit"
    end
    
  3. In the root directory of your project, run pod update.

    For more information about CocoaPods, see CocoaPods Guides.

Initialize module

Follow the instructions in Fast Integration with Smart Life App SDK for iOS and initialize the SDK. Then, initialize the Matter module.

// Initialize the SDK.
[[TuyaSmartSDK sharedInstance] startWithAppKey:<#your_app_key#> secretKey:<#your_secret_key#>];

// Initialize the Matter module.
[ThingSmartMatterActivatorConfig setMatterConfigKey:<#YOUR_APP_GROUP_ID#>];

API description

+ (void)setMatterConfigKey:(NSString *)configKey;

Parameters

Parameter Description
configKey The App Group ID of the project.

Example

Objective-C:

[ThingSmartMatterActivatorConfig setMatterConfigKey:<#YOUR_APP_GROUP_ID#>];

Swift:

ThingSmartMatterActivatorConfig.setMatterKey("YOUR_APP_GROUP_ID")

Configure and integrate with Extension Target

Things to note

  • Xcode 14.1 or later is required.
  • iOS 16.1 or later is required.
  • Create Matter Extension Target and use the default code file to perform the steps described in the following sections.
  • Matter Extension Target supports Swift projects only.

Configure entitlements

  1. Open the project settings in Xcode.
  2. Choose the target of the main project > Signing & Capabilities, and click + Capability.
  3. Add the App Groups entitlement that is used to share data with the target of the main project. Set App Group ID to the same value as the target of the main project.

Use CocoaPods for fast integration

  1. We recommend that you update CocoaPods to the latest version.

  2. Add the following code block to the Podfile:

    platform :ios, '9.0'
    
    target 'Your_Matter_Extension_Target_Name' do
        pod "ThingSmartMatterExtensionKit"
    end
    
  3. In the root directory of your project, run pod update.

    For more information about CocoaPods, see CocoaPods Guides.

Initialize module

Open the file RequestHandler.swift in the ExtensionTarget project and rewrite the init method.

override init()

API description

+ (void)setMatterConfigKey:(NSString *)configKey;

Parameters

Parameter Description
configKey The App Group ID of the project.

Example

Swift:

override init() {
  super.init()
  ThingMatterExtensionSupport.shared.setMatterConfigKey(configKey: <#YOUR_APP_GROUP_ID#>)
}

Use ThingSmartMatterExtensionKit

After the Matter Extension Target project is generated, the file RequestHandler.swift appears in the Extension project. Use the API methods provided by the system and call ThingSmartMatterExtensionKit as shown in the following example.

  1. Import ThingSmartMatterExtensionKit into the project.

    import ThingSmartMatterExtensionKit
    
  2. Make API requests with the methods that are automatically generated by the system, as shown in the following code block.

    The callback methods in RequestHandler.swift are automatically generated by the system and cannot be modified.

        override func validateDeviceCredential(_ deviceCredential: MatterAddDeviceExtensionRequestHandler.DeviceCredential) async throws {
            ThingMatterExtensionSupport.shared.validateDeviceCredential(deviceCredential)
        }
    
        override func selectWi-FiNetwork(from wifiScanResults: [MatterAddDeviceExtensionRequestHandler.Wi-FiScanResult]) async throws -> MatterAddDeviceExtensionRequestHandler.Wi-FiNetworkAssociation {
            // Use this function to select a Wi-Fi network for the device if your ecosystem has special requirements.
            // Or, return `.defaultSystemNetwork` to use the iOS device's current network.
            return ThingMatterExtensionSupport.shared.selectWi-FiNetwork(from: wifiScanResults)
        }
    
        override func selectThreadNetwork(from threadScanResults: [MatterAddDeviceExtensionRequestHandler.ThreadScanResult]) async throws -> MatterAddDeviceExtensionRequestHandler.ThreadNetworkAssociation {
            // Use this function to select a Thread network for the device if your ecosystem has special requirements.
            // Or, return `.defaultSystemNetwork` to use the default Thread network.
            return ThingMatterExtensionSupport.shared.selectThreadNetwork(from: threadScanResults)
        }
    
        override func commissionDevice(in home: MatterAddDeviceRequest.Home?, onboardingPayload: String, commissioningID: UUID) async throws {
            // Use this function to commission the device with your Matter stack.
            ThingMatterExtensionSupport.shared.commissionDevice(in: home, onboardingPayload: onboardingPayload, commissioningID: commissioningID)
        }
    
        override func rooms(in home: MatterAddDeviceRequest.Home?) async -> [MatterAddDeviceRequest.Room] {
            // Use this function to return the rooms your ecosystem manages.
            // If your ecosystem manages multiple homes, ensure you are returning rooms that belong to the provided home.
            return ThingMatterExtensionSupport.shared.rooms(in: home)
        }
    
        override func configureDevice(named name: String, in room: MatterAddDeviceRequest.Room?) async {
            // Use this function to configure the (now) commissioned device with the given name and room.
            ThingMatterExtensionSupport.shared.configureDevice(named: name, in: room)
        }
    

Configure Matter capabilities

Due to the characteristics of a Matter device, all its capabilities are implemented based on Matter fabrics. Before a Matter device can be paired, controlled, or managed, you must make API requests to configure basic information about the Matter device. This configuration must be finished before any Matter services are implemented.

A fabric is a group of networked devices (also known as nodes) that share the same security domain. This enables secure communications among these nodes within the fabric. Nodes in the same fabric share the same Certificate Authority’s (CA) top-level certificate (Root of Trust) and within the context of the CA, a unique 64-bit identifier named Fabric ID.

Prepare information about fabric

Information about Matter is bound with homes. Therefore, at the end of the operation of switching between homes or initially loading a home, call - loadFabricWithSpaceId to get information about the fabric that is bound with the home.

API description

@interface ThingSmartMatterManager : NSObject
+ (instancetype)sharedInstance;
- (void)loadFabricWithSpaceId:(long long)spaceId
                success:(ThingSuccessHandler)success
                      failure:(ThingFailureError)failure;
@end

Parameters

Parameter Description
spaceId The value of HomeID for the current home.
success The success callback.
failure The failure callback.

Example

Objective-C:

- (void)loadMatterCurrentHomeFabric:(long long)homeId {
    // Called at the end of the operation of switching between homes or initially loading a home.
    [[ThingSmartMatterManager sharedInstance] loadFabricWithSpaceId:homeId success:^{
        NSLog(@"load fabric success");
    } failure:^(NSError *error) {
        NSLog(@"load fabric fail");
    }];
}

Swift:

func loadMatterCurrentHomeFabric(homeId: Int64) {
    // Called at the end of the operation of switching between homes or initially loading a home.
    ThingSmartMatterManager.sharedInstance().loadFabric(withSpaceId: homeId) {
        print("load fabric success")
    } failure: { error in
        print("load fabric fail")
    }
}

Prepare information about devices

Different from other types of Tuya-enabled devices, certain information about Matter devices must be prepared in advance. For this purpose, at the end of loading home information and fabric information, call - getDevicesFabricNodesWithdevIds:callback: to handle Matter devices for the specified home.

API description

@interface ThingSmartMatterShareManager : NSObject
+ (instancetype)sharedInstance;
- (void)getDevicesFabricNodesWithdevIds:(NSArray <NSString *>*)devIds callback:(void(^)(NSArray <ThingSmartMatterDeviceNodeModel *>*result))callback;
@end

Parameters

Parameter Description
devIds The list of device IDs.

Example

Objective-C:

- (void)loadMatterDeviceInfo {
    // Called at the end of `- loadFabric` and loading devices in the home.
    [[ThingSmartMatterShareManager sharedInstance] getDevicesFabricNodesWithdevIds:deviceIdList callback:^(NSArray<ThingSmartMatterDeviceNodeModel *> *result) {
        NSLog(@"load matter device node succes");
    }];
}

Swift:

func loadMatterDeviceInfo(){
  // Called at the end of `- loadFabric` and loading devices in the home.
  ThingSmartMatterShareManager.sharedInstance().getDevicesFabricNodesWithdevIds(deviceIdList) { modelList in
      print("load matter device info success")
  }
}
## Pairing process
AppBizBundle SDKMatter DeviceCloudDevice enterspairing mode.Parse device's QR code.1Parse device's QRcode.Return device information.2alt[Scan device's QRcode.]Parse the setup code.3Parse the setupcode.Return device information.4alt[Enter the setupcode.]Turn on search and startsearching for Matter devices.5Search for devices.Return the list of discovereddevices.6alt[Search for devices.]Request a pairing token.7Return the pairing token.8Start activating the device.9Start activating andconnecting to the device.10Device is connected.11Device is connected.12Activate the device by deviceinformation.13Activate the device by deviceinformation.14Activate the device with thecloud.15Activated.16Activation completed.17Activation completed.18alt[Activate device.]AppBizBundle SDKMatter DeviceCloudMatter Device Pairing

Register the pairing type

When the device pairing service is initialized, register the pairing type, which is ThingSmartActivatorTypeMatterModel.

API description

/// Initialize network configuration types
/// @param typeList Network configuration types
- (void)registerWithActivatorList:(NSArray<ThingSmartActivatorTypeModel *>*)typeList;

Parameter description

Parameters Description
typeList The list of pairing types.

Get a token

The SDK gets a pairing token from the cloud before it can start the pairing process. The token is valid for 10 minutes and expires immediately after the device is paired. A new token must be generated if the device needs to be paired again.

API description

- (void)getTokenWithHomeId:(long long)homeId
                   success:(ThingSuccessString)success
                   failure:(ThingFailureError)failure;

Parameter description

Parameters Description
homeId The ID of the home with which the device is bound.
success The success callback. A pairing token is returned.
failure The failure callback. An error message is returned.

Parse QR code or manual setup code

Read the QR code or manual setup code. If the code is wrong, the device model is not returned.

/// Check the matter code is legal or not. Returns nil if it is invalid.
/// @param qrString The matter QRCode string or Manual Code string.
- (ThingSmartActivatorDeviceModel *)parseSetupCode:(NSString *)qrString;

Parameter description

Parameters Description
qrString The information read from the QR code or manual setup code.

Start searching

Pass in the registered typeList to start searching.

API description

/// Start searching
/// @param typeList Network configuration types
- (void)startSearch:(NSArray <ThingSmartActivatorTypeModel *>*)typeList;

Parameter description

Parameters Description
typeList The list of pairing types.

Stop searching

API description

/// Stop searching
/// @param typeList Network configuration types
/// @param clearCache Whether to clear the cache
- (void)stopSearch:(NSArray <ThingSmartActivatorTypeModel *>*)typeList clearCache:(BOOL)clearCache;

Parameter description

Parameters Description
typeList The list of pairing types.
clearCache Specifies whether to clear the cache search result.

Device search callback

After the device is discovered, the callback returns the device information. If the operation fails, the callback returns the error message.

API description

/// Device search callback
/// @param service Search instance
/// @param type Network configuration type
/// @param device Discovered device
/// @param errorModel Error callback
- (void)activatorService:(id<ThingSmartActivatorSearchProtocol>)service
            activatorType:(ThingSmartActivatorTypeModel *)type
             didFindDevice:(nullable ThingSmartActivatorDeviceModel *)device
                     error:(nullable ThingSmartActivatorErrorModel *)errorModel;

Parameter description

Parameters Description
service The pairing service.
type The pairing type.
device The discovered device. The device model is returned on success. nil is returned on failure.
errorModel This model is returned if pairing fails or times out. nil is returned on success.

Activate a device

API description

/// Activate devices with a single network configuration type
/// @param type Network configuration type
/// @param deviceList Devices to be activated
- (void)startActive:(ThingSmartActivatorTypeModel *)type deviceList:(NSArray<ThingSmartActivatorDeviceModel *>*)deviceList;

Parameter description

Parameters Description
type The pairing type.
deviceList The list of devices to be activated. Currently, only one device is supported.

Matter pairing option callback

The SDK automatically selects the optimal pairing option based on the advertising data. It then sends the selection to the business layer through the callback for displaying on the respective app page. There are three pairing options: Tuya-specific pairing, sharing and pairing, and MatterSupport.
To enable MatterSupport, see Prepare for Integration with Matter Device. MatterSupport is available only after you configure it for your project.

/// Discoveryed Matter Device.
/// @param typeModel device type model
- (void)matterDeviceDiscoveryed:(ThingMatterDeviceDiscoveriedType *)typeModel;

Parameter description

Parameters Description
typeModel The pairing option.

PASE session establishment callback

After the Matter device is connected, the completion of Password Authenticated Session Establishment (PASE) will invoke the PASE session success callback.

/// Matter commission establish complete, model's type will be known.
/// @param deviceModel Device model.
- (void)matterCommissioningSessionEstablishmentComplete:(ThingSmartActivatorDeviceModel *)deviceModel;

Parameter description

Parameters Description
deviceModel The Matter device model in the PASE session.

Create CASE session and connect device to cloud

With the PASE session, some key information such as device type is obtained. If the device needs to connect to the cloud and the parameters required for Certificate Authenticated Session Establishment (CASE) are ready, you can call this method to establish a CASE session.

/// @param deviceModel the matter devicemodel.
/// @param typeModel Network configuration type.
- (void)continueCommissionDevice:(ThingSmartActivatorDeviceModel *)deviceModel typeModel:(ThingSmartActivatorTypeMatterModel *)typeModel;

Parameter description

Parameters Description
deviceModel The Matter device model returned by the PASE completion callback matterCommissioningSessionEstablishmentComplete.
typeModel The parameter model for a CASE session. For a combo device, ssid and password are required, and for a Thread device, gwDevId is required.

Device attestation callback

The callback to invoke when an attempt is made to pair a device that is not Matter-certified. After this callback is invoked, the pairing process will be suspended until the user chooses to continue or cancel.

// Matter device attestation fails, use `-continueCommissioningDevice:ignoreAttestationFailure:error:` to continue OR interrupt.
///
/// **Notice**
/// Usually app will display an alert view to the user, allowing the user to judge whether to ignore the attestation failure.
///
/// @param device the failure device.
/// @param error the failure error info.
- (void)matterDeviceAttestation:(void *)device error:(NSError * _Nonnull)error;

Parameter description

Parameters Description
device The pointer to the device object address in the pairing process.
error The error message for an uncertified device.

Trust uncertified device and continue pairing

If the user chooses to add an uncertified Matter device, call this method to continue the pairing process.

/// Continue the pairing or NOT.
///
/// **Notice:** Can only be used after the `-matterDeviceAttestation:error:` delegate callback.
///
/// @param device It MUST BE the device object through the `-matterDeviceAttestation:error:` delegate callback.
/// @param ignoreAttestationFailure Ignore the attestation fail or NOT. `YES` - continue pairing, `NO` - interrupt pairing.
/// @param error the error info.
- (void)continueCommissioningDevice:(void *)device
           ignoreAttestationFailure:(BOOL)ignoreAttestationFailure
                              error:(NSError * __autoreleasing *)error;

Parameter description

Parameters Description
device The pointer to the device object address in the device attestation callback method. Be sure to pass in the raw parameter data.
ignoreAttestationFailure Specifies whether to ignore the attestation failure.
error The error message that might be returned in this call.

Activation result callback

// Device network configuration result callback
/// @param service Device network configuration implementation object
/// @param type Network configuration type
/// @param devices Devices being configured
/// @param errorModel Error encountered during network configuration
- (void)activatorService:(id<ThingSmartActivatorActiveProtocol>)service
           activatorType:(ThingSmartActivatorTypeModel *)type
       didReceiveDevices:(nullable NSArray<ThingSmartActivatorDeviceModel *> *)devices
                   error:(nullable ThingSmartActivatorErrorModel *)errorModel;

Parameter description

Parameters Description
service The pairing service.
type The pairing type.
devices The activated device.
errorModel This model is returned if pairing fails or times out. nil is returned on success.

Stop activation

API description

/// Stop activating devices
/// @param typeList Array of network configuration types
/// @param clearCache Whether to clear the cache
- (void)stopActive:(NSArray <ThingSmartActivatorTypeModel *>*)typeList clearCache:(BOOL)clearCache;

Parameter description

Parameters Description
typeList The pairing type.
clearCache Specifies whether to clear the cache search result.

Error codes

ThingSmartActivatorErrorModel is returned if pairing fails or times out.

@interface ThingSmartActivatorErrorModel : NSObject
@property (nonatomic, strong) ThingSmartActivatorDeviceModel *deviceModel;
@property (nonatomic) NSError *error;
@end

ThingSmartActivatorDiscoveryError includes the definition of error codes.

Example

Search for a device to pair

Swift:

class BEMatterTableViewController: UITableViewController {

    private var typeModel: ThingSmartActivatorTypeMatterModel = {
        let type = ThingSmartActivatorTypeMatterModel()
        type.type = ThingSmartActivatorType.matter
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.matter)
        type.timeout = 180
        return type
    }()

    lazy var discovery: ThingSmartActivatorDiscovery = {
        let discovery = ThingSmartActivatorDiscovery()
        discovery.register(withActivatorList: [self.typeModel])
        discovery.setupDelegate(self)
        discovery.loadConfig()
        return discovery
    }()

    func bindMatter(qrcode codeStr: String?) -> Void {
        let homeId = (Home.current?.homeId)!
        let payload = self.discovery.parseSetupCode(codeStr ?? "")
        let activator = ThingSmartActivator()
        activator.getTokenWithHomeId(homeId, success: { [weak self] (token) in
            guard let self = self else { return }
            self.typeModel.token = token ?? ""
            self.typeModel.spaceId = homeId
            self.discovery.startActive(self.typeModel, deviceList:[payload])
            SVProgressHUD.show(withStatus: NSLocalizedString("Configuring", comment: ""))
        }, failure: { (error) in
            let errorMessage = error?.localizedDescription ?? ""
            SVProgressHUD.showError(withStatus: errorMessage)
        })
    }

    private func stopConfigWifi() {
        SVProgressHUD.dismiss()
        discovery.stopActive([typeModel], clearCache: true)
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        discovery.startSearch([self.typeModel])
    }

}

extension BEMatterTableViewController: ThingSmartActivatorSearchDelegate {
    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {
        if let device = device {
            if device.deviceModelType == ThingSearchDeviceModelTypeMatterWifi {
                self.typeModel.ssid = ssid.text ?? ""
                self.typeModel.password = password.text ?? ""
                print("Please use Dual Mode to pair: %@", device.uniqueID)

            }

            if device.deviceModelType == ThingSearchDeviceModelTypeMatterThread {
                self.typeModel.gwDevId = "gateway deivce id"
            }
            let homeId = (Home.current?.homeId)!
            let payload = self.discovery.parseSetupCode(codeStr ?? "")
            let activator = ThingSmartActivator()
            activator.getTokenWithHomeId(homeId, success: { [weak self] (token) in
                guard let self = self else { return }
                self.typeModel.token = token ?? ""
                self.typeModel.spaceId = homeId
                self.discovery.startActive(self.typeModel, deviceList:[payload])
                SVProgressHUD.show(withStatus: NSLocalizedString("Configuring", comment: ""))
            }, failure: { (error) in
                let errorMessage = error?.localizedDescription ?? ""
                SVProgressHUD.showError(withStatus: errorMessage)
            })
        }

        if let errorModel = errorModel {
            // Error
            SVProgressHUD.showError(withStatus: errorModel.error.localizedDescription)
        }
    }
}

extension BEMatterTableViewController: ThingSmartActivatorActiveDelegate {
    func activatorService(_ service: ThingSmartActivatorActiveProtocol, activatorType type: ThingSmartActivatorTypeModel, didReceiveDevices devices: [ThingSmartActivatorDeviceModel]?, error errorModel: ThingSmartActivatorErrorModel?) {
        if errorModel != nil {
            SVProgressHUD.showError(withStatus: "Bind Failure. (\(errorModel?.error.localizedDescription ?? ""))")
            return
        }

        let device = devices?.first
        isSuccess = true
        SVProgressHUD.show(withStatus: "Bind Success. \n devId: \(device?.uniqueID ?? "") \n name: \(device?.name ?? "")")
    }
}

extension BEMatterTableViewController: ThingSmartActivatorDeviceExpandDelegate {
    func matterDeviceDiscoveryed(_ typeModel: ThingMatterDeviceDiscoveriedType) {
        deviceTypeModel = typeModel
    }

    func matterCommissioningSessionEstablishmentComplete(_ deviceModel: ThingSmartActivatorDeviceModel) {
        if deviceTypeModel?.deviceType == .wifi {
            self.typeModel.ssid = ssid.text ?? ""
            self.typeModel.password = password.text ?? ""
            self.discovery.continueCommissionDevice(deviceModel, typeModel: self.typeModel)
        }

        ///
        if deviceTypeModel?.deviceType == .thread {
            self.typeModel.gwDevId = "your gateway id"
            self.discovery.continueCommissionDevice(deviceModel, typeModel: self.typeModel)
        }

    }

    func matterDeviceAttestation(_ device: UnsafeMutableRawPointer, error: Error) {
        let alertControl = UIAlertController(title: "Attestation", message: "Should Continue?", preferredStyle: .alert)
        let alertAction = UIAlertAction(title: "Continue", style: .default) { _ in
            self.discovery.continueCommissioningDevice(device, ignoreAttestationFailure: true, error: nil)
        }
        let canAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in
            self.discovery.continueCommissioningDevice(device, ignoreAttestationFailure: false, error: nil)
        }

        alertControl.addAction(alertAction)
        alertControl.addAction(canAction)

        self.present(alertControl, animated: true)
    }

}

Objective-C:


- (void)getToken {
    ThingSmartActivator *wiredActivator = [[ThingSmartActivator alloc] init];
    [wiredActivator getTokenWithHomeId:homeId success:^(NSString *token) {
        NSLog(@"getToken success: %@", token);
        [self startConfigWiFi:token];
    } failure:^(NSError *error) {
        NSLog(@"getToken failure: %@", error.localizedDescription);
    }];
}

- (void)startConfigWiFi:(NSString *)token {
  ThingSmartActivatorTypeMatterModel *matterType  = [[ThingSmartActivatorTypeMatterModel alloc] init];
  matterType.type = ThingSmartActivatorTypeMatter;
  matterType.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorTypeMatter);
  matterType.timeout = 120;
  matterType.spaceId = homeId;
  matterType.token = token;

  [self.discovery registerWithActivatorList:@[matterType]];
  [self.discovery setupDelegate:self];
  [self.discovery startSearch:@[matterType]];
}

- (void)activatorService:(id<ThingSmartActivatorSearchProtocol>)service activatorType:(ThingSmartActivatorTypeModel *)type didFindDevice:(ThingSmartActivatorDeviceModel *)device error:(ThingSmartActivatorErrorModel *)errorModel {

    if (errorModel) {
        [self _connectWifiError:errorModel];
        return;
    }

    if (device) {
        [self _handleDevice:device];
    }
}

- (void)_handleDevice:(ThingSmartActivatorDeviceModel *)deviceModel {
     ThingSmartActivatorTypeMatterModel *matterType = (ThingSmartActivatorTypeMatterModel *)[self.discovery activatorTypeModelWith:ThingSmartActivatorTypeMatter];
    [self.discovery startActive:matterType deviceList:@[deviceModel]];
}


- (void)matterRoutingComplete:(ThingSmartMatterRoutingType)routingType {
    self.routingType = routingType;
    if (routingType == ThingSmartMatterRoutingTypeSupport) {

    }
}

-(void)matterCommissioningSessionEstablishmentComplete:(ThingSmartActivatorDeviceModel *)deviceModel {


    if (self.routingType == ThingSmartMatterRoutingTypeThing && deviceModel.deviceModelType == ThingSearchDeviceModelTypeMatterThread) {
        self.matterType..gwDevId = gatewayID;
        [self.discovery continueCommissionDevice:deviceModel typeModel:self.matterType];
    }

    if (self.routingType == ThingSmartMatterRoutingTypeThing && deviceModel.deviceModelType == ThingSearchDeviceModelTypeMatterWifi) {

        self.matterType.ssid = factoryConfig.ssid;
        self.matterType.password = factoryConfig.password;
        [self.discovery continueCommissionDevice:deviceModel typeModel:self.matterType];

    }

}

- (void)activatorService:(id<ThingSmartActivatorActiveProtocol>)service
           activatorType:(ThingSmartActivatorTypeModel *)type
       didReceiveDevices:(nullable NSArray<ThingSmartActivatorDeviceModel *> *)devices
                   error:(nullable ThingSmartActivatorErrorModel *)errorModel {
     if (devices && devices.count > 0) {

     }
}

- (ThingSmartActivatorDiscovery *)discovery {
    if (!_discovery) {
        _discovery = [[ThingSmartActivatorDiscovery alloc] init];
    }
    return _discovery;
}

Scan QR code or enter setup code to pair

Swift:

class BEMatterTableViewController: UITableViewController {
   /// UI

    private var typeModel: ThingSmartActivatorTypeMatterModel = {
        let type = ThingSmartActivatorTypeMatterModel()
        type.type = ThingSmartActivatorType.matter
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.matter)
        type.timeout = 180
        return type
    }()

    lazy var discovery: ThingSmartActivatorDiscovery = {
        let discovery = ThingSmartActivatorDiscovery()
        discovery.register(withActivatorList: [self.typeModel])
        discovery.setupDelegate(self)
        discovery.loadConfig()
        return discovery
    }()

    func bindMatter(qrcode codeStr: String?) -> Void {
        let homeId = (Home.current?.homeId)!
        let payload = self.discovery.parseSetupCode(codeStr ?? "")
        let activator = ThingSmartActivator()
        activator.getTokenWithHomeId(homeId, success: { [weak self] (token) in
            guard let self = self else { return }
            self.typeModel.token = token ?? ""
            self.typeModel.spaceId = homeId
            self.discovery.startActive(self.typeModel, deviceList:[payload])
            SVProgressHUD.show(withStatus: NSLocalizedString("Configuring", comment: ""))
        }, failure: { (error) in
            let errorMessage = error?.localizedDescription ?? ""
            SVProgressHUD.showError(withStatus: errorMessage)
        })
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let vc = QRCodeScanerViewController()
        vc.scanCallback = { [weak self] codeStr in
            self?.bindMatter(qrcode: codeStr)
        }
        navigationController?.pushViewController(vc, animated: true)
    }

}

extension BEMatterTableViewController: ThingSmartActivatorActiveDelegate {
    func activatorService(_ service: ThingSmartActivatorActiveProtocol, activatorType type: ThingSmartActivatorTypeModel, didReceiveDevices devices: [ThingSmartActivatorDeviceModel]?, error errorModel: ThingSmartActivatorErrorModel?) {
        if errorModel != nil {
            SVProgressHUD.showError(withStatus: "Bind Failure. (\(errorModel?.error.localizedDescription ?? ""))")
            return
        }

        let device = devices?.first
        isSuccess = true
        SVProgressHUD.show(withStatus: "Bind Success. \n devId: \(device?.uniqueID ?? "") \n name: \(device?.name ?? "")")
    }
}

extension BEMatterTableViewController: ThingSmartActivatorDeviceExpandDelegate {
    func matterDeviceDiscoveryed(_ typeModel: ThingMatterDeviceDiscoveriedType) {
        deviceTypeModel = typeModel
    }

    func matterCommissioningSessionEstablishmentComplete(_ deviceModel: ThingSmartActivatorDeviceModel) {
        if deviceTypeModel?.deviceType == .wifi {
            self.typeModel.ssid = ssid.text ?? ""
            self.typeModel.password = password.text ?? ""
            self.discovery.continueCommissionDevice(deviceModel, typeModel: self.typeModel)
        }

        ///
        if deviceTypeModel?.deviceType == .thread {
            self.typeModel.gwDevId = "your gateway id"
            self.discovery.continueCommissionDevice(deviceModel, typeModel: self.typeModel)
        }

    }

    func matterDeviceAttestation(_ device: UnsafeMutableRawPointer, error: Error) {
        let alertControl = UIAlertController(title: "Attestation", message: "Should Continue?", preferredStyle: .alert)
        let alertAction = UIAlertAction(title: "Continue", style: .default) { _ in
            self.discovery.continueCommissioningDevice(device, ignoreAttestationFailure: true, error: nil)
        }
        let canAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in
            self.discovery.continueCommissioningDevice(device, ignoreAttestationFailure: false, error: nil)
        }

        alertControl.addAction(alertAction)
        alertControl.addAction(canAction)

        self.present(alertControl, animated: true)
    }

}

Objective-C:


- (void)getToken {
    ThingSmartActivator *wiredActivator = [[ThingSmartActivator alloc] init];
    [wiredActivator getTokenWithHomeId:homeId success:^(NSString *token) {
        NSLog(@"getToken success: %@", token);
        [self startConfigWiFi:token];
    } failure:^(NSError *error) {
        NSLog(@"getToken failure: %@", error.localizedDescription);
    }];
}

- (void)startConfigWiFi:(NSString *)token {
  ThingSmartActivatorTypeMatterModel *matterType  = [[ThingSmartActivatorTypeMatterModel alloc] init];
  matterType.type = ThingSmartActivatorTypeMatter;
  matterType.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorTypeMatter);
  matterType.timeout = 120;
  matterType.spaceId = homeId;
  matterType.token = token;

  [self.discovery registerWithActivatorList:@[matterType]];
  [self.discovery setupDelegate:self];

  ThingSmartActivatorDeviceModel *deviceModel = [self.discovery parseSetupCode:code];
  if (deviceModel) {
    [self.discovery startActive:matterType deviceList:@[deviceModel]];
  } else {

  }
}
//Follow-up processing logic is consistent with search activate