Device Pairing

Last Updated on : 2024-08-19 07:42:55download

This topic describes the device pairing service, including Bluetooth devices, wired devices, Zigbee devices, and Matter devices.

Bluetooth device

Bluetooth devices encompass Bluetooth Low Energy (LE), Bluetooth mesh, Bluetooth combo devices, and beacon devices. They can be discovered through a Bluetooth scan and then paired. This section describes how to use the BizBundle SDK to implement hybrid Bluetooth pairing.

Prerequisites

  • Add the following declarations in info.plist.

    Device Pairing
  • Turn on Bluetooth on the mobile phone and grant the app permission to access Bluetooth. If the app does not have Bluetooth permissions, prompt the user to grant access.

    Device Pairing Device Pairing

Search

Search for different types of Bluetooth devices simultaneously.

class BleScanModeTableViewController: UIViewController {

    var deviceList:[ThingSmartActivatorDeviceModel] = []

    private var bleModel: ThingSmartActivatorTypeBleModel = {
        let type = ThingSmartActivatorTypeBleModel()
        type.type = ThingSmartActivatorType.ble
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.ble)
        type.timeout = 120
        if let currentHome = Home.current {
            type.spaceId = currentHome.homeId
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return type
    }()

    private var sigModel: ThingSmartActivatorTypeSigMeshModel = {
        let type = ThingSmartActivatorTypeSigMeshModel()
        type.type = ThingSmartActivatorType.sigMesh
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.sigMesh)
        type.timeout = 120
        if let currentHome = Home.current {
            type.spaceId = currentHome.homeId
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return type
    }()

    private var beaconModel: ThingSmartActivatorTypeBeaconModel = {
        let type = ThingSmartActivatorTypeBeaconModel()
        type.type = ThingSmartActivatorType.beacon
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.beacon)
        type.timeout = 120
        return type
    }()

    lazy var discovery: ThingSmartActivatorDiscovery = {
        let discovery = ThingSmartActivatorDiscovery()
        discovery.register(withActivatorList: [self.bleModel,self.sigModel,self.beaconModel])
        discovery.setupDelegate(self)
        discovery.loadConfig()
        if let currentHome = Home.current {
            discovery.currentSpaceId(currentHome.homeId)
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return discovery
    }()

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        stopConfiguring()
    }

    @IBAction func searchTapped(_ sender: UIBarButtonItem) {
        discovery.startSearch([self.bleModel,self.sigModel,self.beaconModel])

        SVProgressHUD.show(withStatus: NSLocalizedString("Searching", comment: ""))

    }

    // MARK: - Private method
    private func stopConfiguring() {
        discovery.stopSearch([self.bleModel,self.sigModel,self.beaconModel], clearCache: true)
        discovery.stopActive([self.bleModel,self.sigModel,self.beaconModel], clearCache: true)
        discovery.removeDelegate(self)
    }
}

// MARK: - ThingSmartActivatorSearchDelegate
extension BleScanModeTableViewController: ThingSmartActivatorSearchDelegate {
    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {

        if var device = device {
            deviceList.append(device)
            // display devices
        }
    }

}

Pairing

The required pairing parameters may vary depending on the type of Bluetooth devices.

Device type Pairing information
ThingSearchDeviceModelTypeBle Pair a single device, no additional parameters required.
ThingSearchDeviceModelTypeSigMeshSubDevice Pair multiple devices in one go, no additional parameters required.
ThingSearchDeviceModelTypeBeacon Pair multiple devices in one go, no additional parameters required.
ThingSearchDeviceModelTypeBleWifi Pair a single device, with Wi-Fi name and password required.
private func startConfiguration(_ deviceModel: ThingSmartActivatorDeviceModel) {
        if deviceModel.deviceModelType == ThingSearchDeviceModelTypeBle {
            discovery.startActive(self.bleModel, deviceList: [deviceModel])
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeBleWifi {
            self.bleModel.ssid = "name of the router"
            self.bleModel.password = "password of the router"
            discovery.startActive(self.bleModel, deviceList: [deviceModel])
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeSigMeshSubDevice {
            var sigMeshList:[ThingSmartActivatorDeviceModel] = []
            for device in deviceList {
                if device.deviceModelType == ThingSearchDeviceModelTypeSigMeshSubDevice {
                    sigMeshList.append(device)
                }
            }

            discovery.startActive(self.sigModel, deviceList: sigMeshList)
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeBeacon {
            var beaconList:[ThingSmartActivatorDeviceModel] = []
            for device in deviceList {
                if device.deviceModelType == ThingSearchDeviceModelTypeBeacon {
                    beaconList.append(device)
                }
            }

            discovery.startActive(self.beaconModel, deviceList: beaconList)
        }
    }

Callback

When pairing devices of different types, compare the returned device information with the selected devices, especially when pairing multiple devices simultaneously.

extension BleScanModeTableViewController: ThingSmartActivatorActiveDelegate {
    func activatorService(_ service: ThingSmartActivatorActiveProtocol, activatorType type: ThingSmartActivatorTypeModel, didReceiveDevices devices: [ThingSmartActivatorDeviceModel]?, error errorModel: ThingSmartActivatorErrorModel?) {
        if errorModel != nil {
            var failureDevice: ThingSmartActivatorDeviceModel?
            if errorModel?.deviceModel != nil {
                self.deviceList.forEach { obj in
                    if ((errorModel?.deviceModel!.isEqual(toDevice: obj)) != nil) {
                        failureDevice = obj
                    }
                }
            }

            SVProgressHUD.showError(withStatus: NSLocalizedString("Failed to Activate Device \(String(describing: failureDevice?.name))", comment: ""))
            return
        }

        if let devices = devices {
            let device = devices.first
            var successDevice: ThingSmartActivatorDeviceModel?

            self.deviceList.forEach { obj in
                if device!.isEqual(toDevice: obj) {
                    successDevice = obj
                }
            }

            successDevice?.deviceStatus = ThingSearchDeviceStatusNetwork
        }
    }
}

Wired device

Prerequisites

  • The mobile phone and the wired gateway are connected to the same router.

  • The app has been granted permission to access the local network.

    Device Pairing

Search

Case 1: Scan for devices along with other scan capabilities.

Your app scans for multiple types of devices at the same time, such as Bluetooth and wired gateways. In this case, the Bluetooth device calls the scan method in the Bluetooth SDK, while the wired gateway calls the scan method in other SDKs, leading to inconsistent result models. Identifying composite-protocol devices is complex, as they can be discovered and paired using various scan methods.

To simplify the pairing process, you can use the composite scan capability, which abstracts the differences of various protocols with a unified method and model.

class CompositeScanModeTableViewController: UIViewController {

    var deviceList:[ThingSmartActivatorDeviceModel] = []

    private var wiredModel: ThingSmartActivatorTypeWiredModel = {
        let type = ThingSmartActivatorTypeWiredModel()
        type.type = .wired
        type.typeName = NSStringFromThingSmartActivatorType(.wired)
        type.timeout = 120
        if let currentHome = Home.current {
            type.spaceId = currentHome.homeId
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return type
    }()

    private var bleModel: ThingSmartActivatorTypeBleModel = {
        let type = ThingSmartActivatorTypeBleModel()
        type.type = ThingSmartActivatorType.ble
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.ble)
        type.timeout = 120
        if let currentHome = Home.current {
            type.spaceId = currentHome.homeId
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return type
    }()

    private var sigModel: ThingSmartActivatorTypeSigMeshModel = {
        let type = ThingSmartActivatorTypeSigMeshModel()
        type.type = ThingSmartActivatorType.sigMesh
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.sigMesh)
        type.timeout = 120
        if let currentHome = Home.current {
            type.spaceId = currentHome.homeId
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return type
    }()

    private var beaconModel: ThingSmartActivatorTypeBeaconModel = {
        let type = ThingSmartActivatorTypeBeaconModel()
        type.type = ThingSmartActivatorType.beacon
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.beacon)
        type.timeout = 120
        return type
    }()

    lazy var discovery: ThingSmartActivatorDiscovery = {
        let discovery = ThingSmartActivatorDiscovery()
        discovery.register(withActivatorList: [self.bleModel,self.sigModel,self.beaconModel])
        discovery.setupDelegate(self)
        discovery.loadConfig()
        if let currentHome = Home.current {
            discovery.currentSpaceId(currentHome.homeId)
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return discovery
    }()

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        stopConfiguring()
    }

    @IBAction func searchTapped(_ sender: UIBarButtonItem) {
        discovery.startSearch([self.wiredModel,self.bleModel,self.sigModel,self.beaconModel])

        SVProgressHUD.show(withStatus: NSLocalizedString("Searching", comment: ""))

    }

    // MARK: - Private method
    private func stopConfiguring() {
        discovery.stopSearch([self.wiredModel,self.bleModel,self.sigModel,self.beaconModel], clearCache: true)
        discovery.stopActive([self.wiredModel,self.bleModel,self.sigModel,self.beaconModel], clearCache: true)
        discovery.removeDelegate(self)
    }

    private func startConfiguration(_ deviceModel: ThingSmartActivatorDeviceModel) {
      // Omit features
    }
}

// MARK: - ThingSmartActivatorSearchDelegate
extension CompositeScanModeTableViewController: ThingSmartActivatorSearchDelegate {
    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {

        if var device = device {
            deviceList.append(device)
            // display devices
        }
    }

}

Composite scan enables the discovered Bluetooth device and wired gateway to be returned with the same callback and unified data entity, eliminating the need for data unity and unique identifiers. Then, the discovered device can be paired using the corresponding pairing capability.

Case 2: Independent scanning

class BEZigbeeGatewayViewController: UIViewController {

    // MARK: - Property
    private var token: String = ""
    private var isSuccess = false
    @IBOutlet weak var tableview: UITableView!
    var deviceList:[ThingSmartActivatorDeviceModel] = []

    private var typeModel: ThingSmartActivatorTypeWiredModel = {
        let type = ThingSmartActivatorTypeWiredModel()
        type.type = ThingSmartActivatorType.wired
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.wired)
        type.timeout = 120
        if let currentHome = Home.current {
            type.spaceId = currentHome.homeId
        } else {
            assert((Home.current != nil),"Home cannot be nil, need to create a Home")
        }
        return type
    }()

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

    // MARK: - Lifecycle

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        stopConfigWifi()
    }

    // MARK: - IBAction
    @IBAction func searchTapped(_ sender: UIBarButtonItem) {
        discovery.startSearch([self.typeModel])
        SVProgressHUD.show(withStatus: NSLocalizedString("Searching", comment: ""))
    }


    private func stopConfigWifi() {
        if !isSuccess {
            SVProgressHUD.dismiss()
        }
        discovery.stopActive([self.typeModel], clearCache: true)
        discovery.removeDelegate(self)
    }
}

extension BEZigbeeGatewayViewController: ThingSmartActivatorSearchDelegate {
    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {
        if (device != nil) {
            SVProgressHUD.dismiss()
            deviceList.append(device!)
            tableview.reloadData()
        }
    }

    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didUpdateDevice device: ThingSmartActivatorDeviceModel) {

    }

}

Device pairing

During device pairing, you can identify the device type with the parameters of the device model deviceModelType.

class CompositeScanModeTableViewController: UIViewController {

    // Omit other features

    private func startConfiguration(_ deviceModel: ThingSmartActivatorDeviceModel) {
        if deviceModel.deviceModelType == ThingSearchDeviceModelTypeBle {
            discovery.startActive(self.bleModel, deviceList: [deviceModel])
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeBleWifi {
            self.bleModel.ssid = "name of the router"
            self.bleModel.password = "password of the router"
            discovery.startActive(self.bleModel, deviceList: [deviceModel])
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeSigMeshSubDevice {
            var sigMeshList:[ThingSmartActivatorDeviceModel] = []
            for device in deviceList {
                if device.deviceModelType == ThingSearchDeviceModelTypeSigMeshSubDevice {
                    sigMeshList.append(device)
                }
            }

            discovery.startActive(self.sigModel, deviceList: sigMeshList)
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeBeacon {
            var beaconList:[ThingSmartActivatorDeviceModel] = []
            for device in deviceList {
                if device.deviceModelType == ThingSearchDeviceModelTypeBeacon {
                    beaconList.append(device)
                }
            }

            discovery.startActive(self.beaconModel, deviceList: beaconList)
        } else if deviceModel.deviceModelType == ThingSearchDeviceModelTypeWired  {

            guard let homeID = Home.current?.homeId else { return }
            SVProgressHUD.show(withStatus: NSLocalizedString("Requesting for Token", comment: ""))

            ThingSmartActivator.sharedInstance()?.getTokenWithHomeId(homeID, success: { [weak self] (token) in
                guard let self = self else { return }
                self.wiredModel.token = "token"
                discovery.startActive(self.wiredModel, deviceList: [deviceModel])
            }, failure: { (error) in
                let errorMessage = error?.localizedDescription ?? ""
                SVProgressHUD.showError(withStatus: errorMessage)
            })
        }
    }
}
extension CompositeScanModeTableViewController: ThingSmartActivatorActiveDelegate {
    func activatorService(_ service: ThingSmartActivatorActiveProtocol, activatorType type: ThingSmartActivatorTypeModel, didReceiveDevices devices: [ThingSmartActivatorDeviceModel]?, error errorModel: ThingSmartActivatorErrorModel?) {
        if errorModel != nil {
            var failureDevice: ThingSmartActivatorDeviceModel?
            if errorModel?.deviceModel != nil {
                self.deviceList.forEach { obj in
                    if ((errorModel?.deviceModel!.isEqual(toDevice: obj)) != nil) {
                        failureDevice = obj
                    }
                }
            }

            SVProgressHUD.showError(withStatus: NSLocalizedString("Failed to Activate Device \(String(describing: failureDevice?.name))", comment: ""))
            return
        }

        if let devices = devices {
            let device = devices.first
            var successDevice: ThingSmartActivatorDeviceModel?

            self.deviceList.forEach { obj in
                if device!.isEqual(toDevice: obj) {
                    successDevice = obj
                }
            }

            successDevice?.deviceStatus = ThingSearchDeviceStatusNetwork
        }
    }
}

Zigbee device

Prerequisites

A Zigbee device relies on a Zigbee gateway to connect to the cloud. Therefore, the pairing process requires a specific gateway that processes device activation and notifications. The target gateway must be online.

  1. Filter the devices in the current home.

  2. Find suitable Zigbee gateways and make sure they are online.

  3. Select the preferred gateway.

  4. If there is no suitable gateway, prompt the user to add one.

        var gatewayList: [ThingSmartDeviceModel] = []
        private func getGatewayList() {
            if Home.current != nil {
                home = ThingSmartHome(homeId: Home.current!.homeId)
    
                guard let list = home?.deviceList else { return }
                gatewayList = list.filter { $0.deviceType == ThingSmartDeviceModelTypeZigbeeGateway && $0.isOnline == true}
            }
        }
    

Search

The discovery of the Zigbee device indicates successful pairing.

class BEZigbeeSubdeviceTableViewController: UITableViewController {

    // MARK: - IBOutlet
    @IBOutlet weak var gatewayNameLabel: UILabel!

    // MARK: - Property
    var gateway: ThingSmartDeviceModel?
    private var isSuccess = false
    var deviceList:[ThingSmartActivatorDeviceModel] = []

    private var typeModel: ThingSmartActivatorTypeSubDeviceModel = {
        let type = ThingSmartActivatorTypeSubDeviceModel()
        type.type = ThingSmartActivatorType.subDevice
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.subDevice)
        type.timeout = 120
        return type
    }()

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

    // MARK: - Lifecycle
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        gatewayNameLabel.text = gateway?.name
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        stopConfiguring()
    }

    override func viewDidLoad() {

    }

    private func stopConfiguring() {
        guard let deviceID = gateway?.devId else { return }

        if !isSuccess {
            SVProgressHUD.dismiss()
        }
        discovery.stopSearch([typeModel], clearCache: true)
        discovery.stopActive([typeModel], clearCache: true)
        discovery.removeDelegate(self)
    }

    // MARK: - Navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard segue.identifier == "Choose Gateway",
              let vc = segue.destination as? BEChooseGatewayTableViewController
        else { return }

        vc.selectedGateway = gateway
        vc.delegate = self
    }

    // MARK: - IBAction
    @IBAction func searchTapped(_ sender: UIBarButtonItem) {
        guard let gateway = gateway else {
            Alert.showBasicAlert(on: self, with: NSLocalizedString("Select Zigbee Gateway", comment: ""), message: NSLocalizedString("You must have one Zigbee gateway selected.", comment: ""))
            return
        }

        SVProgressHUD.show(withStatus: NSLocalizedString("Configuring", comment: ""))
        typeModel.gwDevId = gateway.devId
        discovery.startSearch([typeModel])
    }

    // MARK: - Table view data source
}

extension BEZigbeeSubdeviceTableViewController: ThingSmartActivatorSearchDelegate {
    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {
        if device != nil && errorModel == nil {
            // Success
            let name = device?.name ?? NSLocalizedString("Unknown Name", comment: "Unknown name device.")
            SVProgressHUD.showSuccess(withStatus: NSLocalizedString("Successfully Added \(name)", comment: "Successfully added one device."))
            isSuccess = true

            SVProgressHUD.dismiss()
        }

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

    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didUpdateDevice device: ThingSmartActivatorDeviceModel) {

    }
}

Matter device

This section describes how to pair a Matter device through searching. For pairing with QR code, see Matter Pairing Implementation in the iOS Home SDK Sample.

Prerequisites

Search

Create a ThingSmartActivatorTypeMatterModel object to search for devices. spaceId is a required parameter.

class BEMatterTableViewController: UITableViewController {


    @IBOutlet weak var ssid: UITextField!
    @IBOutlet weak var password: UITextField!
    var deviceTypeModel: ThingMatterDeviceDiscoveriedType?
    private var isSuccess = false
    var deviceList: [ThingSmartActivatorDeviceModel] = []

    /// UI
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Matter"
        startSearchMatter()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        stopConfigWifi()
    }

    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
    }()

    private func startSearchMatter () {
        let homeId = (Home.current?.homeId)!
        self.typeModel.spaceId = homeId;
        self.discovery.startSearch([self.typeModel])
    }

}

extension BEMatterTableViewController: ThingSmartActivatorSearchDelegate {
    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {
        if device != nil {
            SVProgressHUD.show(withStatus: "Search device: (\(device?.name ?? ""))")
            deviceList.append(device!)
            tableView.reloadData()
            return
        }
    }
}

Pairing

The pairing parameters differ depending on the type of Matter devices. For example, Wi-Fi devices require the name and password of the Wi-Fi network, while Thread devices require the ID of the gateway. See the example code.

class BEMatterTableViewController: UITableViewController {

    // The code for device search is omitted here.

    private func startBindMatter(with deviceModel:ThingSmartActivatorDeviceModel) -> Void {
        let homeId = (Home.current?.homeId)!
        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:[deviceModel])
            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) {
        startBindMatter(with: deviceList[indexPath.row])
    }

}

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)
    }

}

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 ?? "")")
    }
}

Common errors

Strong binding error

If an error message indicates that the device is already bound, it must be unbound before being paired again. Using the FAQ UI BizBundle, guide users to the FAQ and Feedback module for submitting an unbinding request.
Add the dependency ThingSmartHelpCenterBizBundle in the podfile, and then run the command pod update to pull the code.

target 'TuyaAppSDKSample-iOS-Swift' do
  use_modular_headers!

  pod 'SVProgressHUD'
  pod 'SGQRCode', '~> 4.1.0'

  # Build and get ThingSmartCryption from iot.tuya.com
    # After purchasing the App SDK official edition, you need to build the SDK again on the Tuya Developer Platform and integrate this new SDK.
    # ./ indicates that the `ios_core_sdk.tar.gz` file will be extracted in the same directory as the `podfile`.
    # To change the storage location, modify `path` to your desired location.
  pod 'ThingSmartCryption', :path => '../ios_core_sdk'
  pod 'ThingSmartHomeKit', '~> 5.2.0'
  pod 'ThingSmartBusinessExtensionKit'
  pod 'ThingSmartBusinessExtensionKitBLEExtra'
  # Add FAQ UI BizBundle
  pod 'ThingSmartHelpCenterBizBundle'

end

If the error code is ThingSmartActivatorDiscoveryErrorDeviceAlreadyBound, you can trigger the unbinding logic.

extension BEBLEModeViewController: ThingSmartActivatorActiveDelegate {
    func activatorService(_ service: ThingSmartActivatorActiveProtocol, activatorType type: ThingSmartActivatorTypeModel, didReceiveDevices devices: [ThingSmartActivatorDeviceModel]?, error errorModel: ThingSmartActivatorErrorModel?) {
        if (errorModel != nil) {
            if let error = errorModel?.error {
                let errorCode = (error as NSError).code
                if (errorCode == ThingSmartActivatorDiscoveryErrorDeviceAlreadyBound.rawValue) {
                    let impl = ThingSmartBizCore.sharedInstance().service(of:ThingFeedBackProtocol.self) as? ThingFeedBackProtocol
                    impl?.gotFeedBackViewController?(withHdType: 8, deviceName:errorModel?.deviceModel?.name, hdId: errorModel?.deviceModel?.devId, uuid: errorModel?.deviceModel?.uniqueID, region:ThingSmartUser.sharedInstance().regionCode, withoutRefresh: true)
                }

            }
            SVProgressHUD.showError(withStatus: NSLocalizedString("Failed to Activate BLE Device", comment: ""))
            return
        }
    }
}

You can enable or disable the strong binding feature on the Tuya Developer Platform.

  1. Log in to the Tuya Developer Platform.

  2. Select a product and click Develop in the Operation column.

  3. In the Function Definition step, scroll down to Advanced Functions and find Device Binding Mode. Toggle it on or off as desired.

    Device Pairing

Two-way binding

Device binding is restricted by both the PID and the app. You can specify the app that a PID can be bound with and the device that an app can be connected to. A device can only be bound when both the app and the device meet the restriction. By default, there are no restrictions for both the PID and app, allowing them to be connected freely.

The error code ThingSmartActivatorDiscoveryErrorAPPUnsupportProduct indicates that special biding rules exist. To modify the rules, submit a service ticket.

func activatorService(_ service: ThingSmartActivatorActiveProtocol, activatorType type: ThingSmartActivatorTypeModel, didReceiveDevices devices: [ThingSmartActivatorDeviceModel]?, error errorModel: ThingSmartActivatorErrorModel?) {
        if (errorModel != nil) {
            if let error = errorModel?.error {
                let errorCode = (error as NSError).code
                if (errorCode == ThingSmartActivatorDiscoveryErrorAPPUnsupportProduct.rawValue) {
                    //
                }
            }
            SVProgressHUD.showError(withStatus: NSLocalizedString("Failed to Activate BLE Device", comment: ""))
            return
        }

    }