设备配网业务拓展

更新时间:2024-01-12 09:31:11下载pdf

此教程介绍设备配网业务,包括蓝牙设备配网、有线配网、Zigbee 设备配网和 Matter 设备配网。

蓝牙设备配网

蓝牙类设备包含蓝牙单点、蓝牙 Mesh、双模设备、Beacon 等类型,都可以通过蓝牙进行搜索,然后再配网。此教程主要介绍如何通过业务扩展 SDK 实现蓝牙设备的混合配网。

前置条件

  • 蓝牙配网首先需要在工程中声明蓝牙权限,在 info.plist 中添加以下声明:

    设备配网业务拓展
  • 需要开启手机蓝牙权限和 App 蓝牙权限。如果用户没有开启,则需要提醒用户开启权限。

    设备配网业务拓展 设备配网业务拓展

设备搜索

蓝牙设备可以组合搜索。

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

}

设备配网

不同的蓝牙设备类型需要的配网参数可能存在差异。

设备类型 配网信息
ThingSearchDeviceModelTypeBle 单个配网,无需其他参数
ThingSearchDeviceModelTypeSigMeshSubDevice 可批量进行配网,无需其他参数
ThingSearchDeviceModelTypeBeacon 可批量进行配网,无需其他参数
ThingSearchDeviceModelTypeBleWifi 单个配网,需要 Wi-Fi 名称和密码
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)
        }
    }

配网结果回调处理

多设备类型进行配网时,需要判断返回的设备信息,与所选择的设备进行匹配,尤其是多设备并行配网时。

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

有线配网

前置条件

  • 在进行有线配网前,确保手机连接的 Wi-Fi 网络和当前有线网关接入的路由器为同一个。

  • App 的本地网络权限需要打开。

    设备配网业务拓展

设备搜索

情况 1:和其他扫描能力一起扫描周围设备

在业务需求下,可能需要同时扫描多种类型的设备。例如蓝牙+有线网关,这时就会出现蓝牙设备调用蓝牙 SDK 扫描方法,有线网关调用其它 SDK 的扫描方法,且结果模型不一致的情况。有时还需要处理复合协议设备通过不同能力发现、配网后是同一个设备的逻辑,处理这些逻辑异常复杂。

此时,推荐使用涂鸦的复合扫描能力,业务拓展 SDK 将这些差异细节屏蔽,使用统一方法和同一个模型来简化配网实现。

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

}

以上方法调用可以将蓝牙和有线网关设备以同一个回调接口和统一的数据实体方式返回,减少了处理数据统一和唯一标识的负责逻辑,方便您使用。下一步配网时,可以直接使用对应的配网能力去配网。

情况 2:独立流程扫描

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

    }

}

设备配网

设备配网时,通过设备模型的 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 设备配网

前置条件

Zigbee 设备依赖 Zigbee 网关连接到云,因此配网过程中必须连接到某个网关,由网关完成设备激活和消息通知。当前所选网关必须为在线状态。

  1. 过滤当前家庭下的设备。

  2. 找出符合条件的 Zigbee 网关,可能存在多个,并确保其在线。

  3. 选择想要的网关。

  4. 若当前家庭下没有符合条件的网关,应提示客户先添加网关设备。

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

设备搜索

搜索到 Zigbee 设备,即配网成功。

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 设备搜索配网

此教程仅介绍 Matter 设备搜索流程配网。如需扫码配网,参考 iOS Home SDK Sample 里的 Matter 配网实现。

前置条件

搜索设备

创建 ThingSmartActivatorTypeMatterModel 对象来搜索设备,注意 spaceId 为必传参数。

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

设备配网

Matter 设备配网时,要注意设备的类型,不同的设备所需配网参数不同。例如,Wi-Fi 设备需要路由器的名称和密码,Thread 设备需要网关设备 ID。详情可参考代码示例。

class BEMatterTableViewController: UITableViewController {

    // 省略搜索部分代码

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

常见错误处理

强绑定错误

遇到设备已经被其他人绑定的错误时,需要解绑处理,解绑服务需要调用 UI 业务包的常见问题与反馈。
首先在 podfile 中添加依赖 ThingSmartHelpCenterBizBundle,然后执行 pod update 命令拉取代码。

target 'TuyaAppSDKSample-iOS-Swift' do
  use_modular_headers!

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

  # 从 iot.tuya.com 构建和获取 ThingSmartCryption
    # 购买正式版后,需重新在 IoT 平台构建 SDK 并重新集成
    # ./ 代表将 `ios_core_sdk.tar.gz` 解压之后所在目录与 `podfile` 同级
    # 若自定义存放目录,可以修改 `path` 为自定义目录层级
  pod 'ThingSmartCryption', :path => '../ios_core_sdk'
  pod 'ThingSmartHomeKit', '~> 5.2.0'
  pod 'ThingSmartBusinessExtensionKit'
  pod 'ThingSmartBusinessExtensionKitBLEExtra'
  # Add FAQ UI BizBundle
  pod 'ThingSmartHelpCenterBizBundle'

end

判断错误码为 ThingSmartActivatorDiscoveryErrorDeviceAlreadyBound,可执行解绑逻辑。

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

关于设备强绑定功能的开启和关闭,可以到涂鸦 IoT 开发平台进行操作。

  1. 登录 涂鸦 IoT 开发平台产品开发

  2. 选择目标产品,单击 操作 栏的 继续开发

  3. 功能定义 页面,下滑页面找到 高级功能 里的 设备绑定模式,单击 操作 栏的开关,开启或者关闭该功能。

    设备配网业务拓展 设备配网业务拓展

PID 双向绑定

PID 与 App 存在两个维度的限制规则。简而言之,在 PID 下可配置该 PID 可被哪个 App 绑定,在 App 下可配置该 App 允许哪些设备连入。只有同时满足 PID 允许该 App 绑定,并且 App 也允许该 PID 接入的情况下,设备绑定才能成功。在默认情况下,PID 与 App 均不存在任何限制规则,可任意连接。

当出现以下报错 ThingSmartActivatorDiscoveryErrorAPPUnsupportProduct 的时候,说明存在特殊的绑定的规则。如需修改,可 提交工单 至运营人员进行配置。

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
        }

    }