替换故障网关

更新时间:2024-08-22 03:23:45下载pdf

使用当前网关设备替换目标网关设备。例如,当一个网关产生故障时,将该网关下的设备一个个地迁移到其它网关下,操作比较繁琐。使用此功能,可以一次性将故障网关下的全部设备迁移到新网关下。

另外,此功能还可以将群组、场景和自动化迁移到新网关下。

接入

source 'https://github.com/tuya/tuya-pod-specs.git'
platform :ios, '11.0'

target 'Your_Project_Name' do
    pod "ThingSmartBusinessExtensionKit"
end

模型

网关替换状态

public enum ThingGatewayTransferStatus {
    case unknown = 0
    case deviceConfigInit = 1
    case deviceDataInit = 2
    case osConfigInit = 3
    case finish = 4
    case failed = 5
    case none = 6
}

网关替换信息

open class ThingGatewayTransferInfo : NSObject {

    /// The device ID of the faulty gateway
    open var targetDeviceId: String

    /// The device name of the faulty gateway
    open var targetDeviceName: String

    /// The device ID of the source gateway
    open var sourceDeviceId: String

    /// The status of transfer
    open var status: ThingGatewayTransferStatus

    /// The failure code, returned when failed
    open var failedCode: String

    /// The time in millisecond when status changed.
    open var time: Double
}

网关替换回调

public protocol ThingGatewayTransferManagerDelegate : NSObjectProtocol {
    func transferManager(_ manager: ThingGatewayTransferManager, statusDidUpdate model: ThingGatewayTransferInfo)
}

网关替换管理类

open class ThingGatewayTransferManager : NSObject {
  ...
}

网关替换管理-类方法

是否支持替换故障网关

在使用替换故障网关功能时,先判断设备是否支持替换故障网关。

本方法是一个类方法,与其功能相同的还有一个实例方法 deviceSupportsTransfer(success:, failure:)

入参 类型 说明
deviceId string 设备 ID
success block 成功回调
failure block 失败回调
/// Determine whether the device supports transfer or not. True means yes, and false means no.
/// - Parameters:
///   - deviceId: the ID of the device which you want to transfer.
///   - success: success callback.
///   - failure: failure callback with error.
open class func deviceSupportsTransfer(_ deviceId: String, success: @escaping (Bool) -> Void, failure: @escaping (Error) -> Void)

获取网关替换信息

通过该接口,您可以查询到当前网关设备的替换状态。在进行替换之前,应该通过本方法查询网关替换信息,确认网关是否正在替换中。

本方法是一个类方法,与其功能相同的还有一个 实例方法 deviceTransferInfo(success:, failure:)

入参 类型 说明
deviceId string 设备 ID
success block 成功回调
failure block 失败回调
/// Get the transfer info of the device.
/// You can only call this method when the 'deviceSupportsTransfer:success:failure:' or 'deviceSupportsTransferWithSuccess:failure:' succeeds with true.
/// - Parameters:
///   - deviceId: the ID of the device which you want to transfer.
///   - success: success callback with ThingGatewayTransferInfo.
///   - failure: failure callback with error.
open class func deviceTransferInfo(withDeviceId deviceId: String, success: @escaping (ThingGatewayTransferInfo) -> Void, failure: @escaping (Error) -> Void)

获取可替换的网关列表

本方法是一个类方法,与其功能相同的还有一个 实例方法 gateways(success:, failure:)

入参 类型 说明
deviceId string 设备 ID
success block 成功回调
failure block 失败回调
/// Get the list of gateways.
/// You can only call this method when the 'deviceSupportsTransfer:success:failure:' or 'deviceSupportsTransferWithSuccess:failure:' succeeded with true.
/// - Parameters:
///   - deviceId: the ID of the device which you want to transfer.
///   - success: success callback with the device ID of gateways.
///   - failure: failure callback with error.
open class func gateways(withDeviceId deviceId: String, success: @escaping ([String]) -> Void, failure: @escaping (Error) -> Void)

进行网关替换

在进行网关替换之前,应先判断设备是否支持网关替换,并判断设备是否在替换中。

本方法是一个类方法,与其功能相同的还有一个 实例方法 transfer(fromGateway:, success:, failure:)

入参 类型 说明
from string 被替换的旧网关的设备 ID
to string 用于替换的新网关的设备 ID
success block 成功回调
failure block 失败回调
/// Transfer the device to the specified gateway.
/// You can only call this method when the 'deviceSupportsTransfer:success:failure:' or 'deviceSupportsTransferWithSuccess:failure:' succeeded with true.
/// - Parameters:
///   - from: the device ID of the old gateway, which is one of the result returned by 'retrieveDeviceTransferGatewaysWithSuccess:failure:'.
///   - to: the device ID of the new gateway.
///   - success: success callback.
///   - failure: failure callback with error.
open class func transfer(fromGateway from: String, toGateway to: String, success: @escaping (ThingGatewayTransferInfo) -> Void, failure: @escaping (Error) -> Void)

网关替换管理-实例方法

是否支持替换故障网关

在使用替换故障网关功能时,先判断设备是否支持替换故障网关。

本方法是一个实例方法,与其功能相同的还有一个 类方法 deviceSupportsTransfer(_:, success:, failure:)

入参 类型 说明
success block 成功回调
failure block 失败回调
/// Determine whether the device supports transfer or not. True means yes, and false means no.
/// - Parameters:
///   - success: success callback.
///   - failure: failure callback with error.
open func deviceSupportsTransfer(success: @escaping (Bool) -> Void, failure: @escaping (Error) -> Void)

获取网关替换信息

通过该接口,您可以查询到当前网关设备的替换状态。在进行替换之前,应该通过本方法查询网关替换信息,确认网关是否正在替换中。

本方法是一个实例方法,与其功能相同的还有一个 类方法 deviceTransferInfo(deviceId:, success:, failure:)

入参 类型 说明
success block 成功回调
failure block 失败回调
/// Get the transfer info of the device.
/// You can only call this method when the 'deviceSupportsTransfer:success:failure:' or 'deviceSupportsTransferWithSuccess:failure:' succeeded with true.
/// - Parameters:
///   - success: success callback with ThingGatewayTransferInfo.
///   - failure: failure callback with error.
open func deviceTransferInfo(success: @escaping (ThingGatewayTransferInfo) -> Void, failure: @escaping (Error) -> Void)

获取可替换的网关列表

本方法是一个实例方法,与其功能相同的还有一个 类方法 gateways(deviceId:, success:, failure:)

入参 类型 说明
success block 成功回调
failure block 失败回调
/// Get the list of gateways.
/// You can only call this method when the 'deviceSupportsTransfer:success:failure:' or 'deviceSupportsTransferWithSuccess:failure:' succeeded with true.
/// - Parameters:
///   - success: success callback with the device ID of gateways.
///   - failure: failure callback with error.
open func gateways(success: @escaping ([String]) -> Void, failure: @escaping (Error) -> Void)

进行网关替换

在进行网关替换之前,应先判断设备是否支持网关替换,并判断设备是否在替换中。

本方法是一个实例方法,与其功能相同的还有一个 类方法 transfer(fromGateway:, toGateway:, success:, failure:)

入参 类型 说明
gatewayId string 被替换网关的设备 ID
success block 成功回调
failure block 失败回调
/// Transfer the device to the specified gateway.
/// You can only call this method when the 'deviceSupportsTransfer:success:failure:' or 'deviceSupportsTransferWithSuccess:failure:' succeeded with true.
/// - Parameters:
///   - gatewayId: the device ID of the gateway, which is one of the result returned by 'retrieveDeviceTransferGatewaysWithSuccess:failure:'.
///   - success: success callback.
///   - failure: failure callback with error.
open func transfer(fromGateway gatewayId: String, success: @escaping (ThingGatewayTransferInfo) -> Void, failure: @escaping (Error) -> Void)

添加监听

入参 类型 说明
listener ThingGatewayTransferManagerDelegate 监听者
/// Add a listener.
/// - Parameter listener: the listener which confirms ThingGatewayTransferManagerDelegate.
open func addListener(_ listener: ThingGatewayTransferManagerDelegate)

移除监听

入参 类型 说明
listener ThingGatewayTransferManagerDelegate 监听者
/// Remove a listener.
/// - Parameter listener: the listener which confirms ThingGatewayTransferManagerDelegate.
open func removeListener(_ listener: ThingGatewayTransferManagerDelegate)

使用示例

更多信息,参考 Demo

import UIKit
import SnapKit

class GatewayTransferController: UIViewController {

    var deviceId: String
    var ids: [String]?

    lazy var label: UILabel = {
        let view = UILabel(frame: CGRectZero)
        view.textColor = UIColor.green
        view.textAlignment = .center
        return view
    }()

    lazy var manager: ThingGatewayTransferManager = {
        let manager = ThingGatewayTransferManager.init(deviceId: self.deviceId)
        return manager
    }()

    lazy var tableview: UITableView = {
        return UITableView(frame: CGRectZero, style: .grouped)
    }()


    init(deviceId: String) {
        self.deviceId = deviceId
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.white
        self.view.addSubview(self.label)
        self.label.snp.makeConstraints { make in
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.top.equalTo(100)
            make.height.equalTo(30)
        }

        self.view.addSubview(self.tableview)
        self.tableview.snp.makeConstraints { make in
            make.left.right.equalTo(0)
            make.top.equalTo(self.label.snp.bottom)
            make.bottom.equalTo(-self.view.safeAreaInsets.bottom)
        }
        self.tableview.delegate = self
        self.tableview.dataSource = self
        self.manager.addListener(self)


        self.loadData()
    }

    func loadData() {
        SVProgressHUD.show()
        self.manager.deviceSupportsTransfer {[weak self] support in

            self?.manager.deviceTransferInfo(success: { info in
                if (info.status == .none) {

                    self?.manager.gateways(success: { ids in
                        self?.ids = ids;
                        self?.label.text = "support"
                        SVProgressHUD.dismiss()

                    }, failure: { e in
                        self?.ids = nil;

                        self?.label.text = "support"
                        SVProgressHUD.dismiss()
                    })

                }else{
                    self?.label.text = "device is transferring"
                    SVProgressHUD.dismiss()
                }
            }, failure: { e in
                self?.label.text = "do not support"
                SVProgressHUD.dismiss()
            })

        } failure: {[weak self] e in
            self?.label.text = "do not support"
            SVProgressHUD.dismiss()
        }
    }
}

extension GatewayTransferController: ThingGatewayTransferManagerDelegate {
    func transferManager(_ manager: ThingGatewayTransferManager, statusDidUpdate model: ThingGatewayTransferInfo) {
        if (model.status == .failed || model.status == .finish) {
            SVProgressHUD.dismiss()
            self.loadData()
        }
    }
}

extension GatewayTransferController: UITableViewDelegate, UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.ids != nil ? self.ids!.count : 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        if cell == nil {
            cell = UITableViewCell(style: .value1, reuseIdentifier: "cell")
        }
        cell?.textLabel?.text = self.ids![indexPath.row]
        return cell!
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.transfer(self.ids![indexPath.row])
    }

    func transfer(_ id: String) {
        SVProgressHUD.show()
        self.manager.transfer(fromGateway: id) { ThingGatewayTransferInfo in

        } failure: { e in

        }
    }

}

展示如何实现简单的替换故障网关功能。

实现一个界面

首先,简单实现一个界面。

  1. 界面初始化的时候,传入 deviceId 作为当前的设备 ID。

  2. 界面会展示一个 UILabel 和一个 UITableView。此时,UILabel 不展示任何文案,UITableView 的分组为 1,行数为 0。另外,将会以 value1 的样式来创建 cell

    import UIKit
    import SnapKit
    
    class GatewayTransferController: UIViewController {
    
        var deviceId: String
    
        lazy var label: UILabel = {
            let view = UILabel(frame: CGRectZero)
            view.textColor = UIColor.green
            view.textAlignment = .center
            return view
        }()
    
        lazy var tableview: UITableView = {
            return UITableView(frame: CGRectZero, style: .grouped)
        }()
    
        init(deviceId: String) {
            self.deviceId = deviceId
            super.init(nibName: nil, bundle: nil)
        }
    
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = UIColor.white
            self.view.addSubview(self.label)
            self.label.snp.makeConstraints { make in
                make.left.equalTo(0)
                make.right.equalTo(0)
                make.top.equalTo(100)
                make.height.equalTo(30)
            }
    
            self.view.addSubview(self.tableview)
            self.tableview.snp.makeConstraints { make in
                make.left.right.equalTo(0)
                make.top.equalTo(self.label.snp.bottom)
                make.bottom.equalTo(-self.view.safeAreaInsets.bottom)
            }
            self.tableview.delegate = self
            self.tableview.dataSource = self
        }
    
    }
    
    extension GatewayTransferController: UITableViewDelegate, UITableViewDataSource {
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 0
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
            if cell == nil {
                cell = UITableViewCell(style: .value1, reuseIdentifier: "cell")
            }
            return cell!
        }
    }
    

加载实例

接下来,懒加载一个 ThingGatewayTransferManager 实例 manager

class GatewayTransferController: UIViewController {
    lazy var manager: ThingGatewayTransferManager = {
        let manager = ThingGatewayTransferManager.init(deviceId: self.deviceId)
        return manager
    }()
}

是否支持替换故障网关

之后,通过 ThingGatewayTransferManager.deviceSupportsTransfer(success:failure:) 接口,判断设备是否支持替换故障网关。

  • 如果支持,则将 label 的文案设置为 support
  • 如果不支持,则将 label 的文案设置为 do not support,且流程到此结束。
class GatewayTransferController: UIViewController {

    override func viewDidLoad() {
        ...
        self.loadData()
    }

    func loadData() {
        SVProgressHUD.show()
        self.manager.deviceSupportsTransfer {[weak self] support in
            self?.label.text = "support"
            SVProgressHUD.dismiss()
        } failure: {[weak self] e in
            self?.label.text = "do not support"
            SVProgressHUD.dismiss()
        }
    }
}

获取迁移状态

当设备支持替换故障网关时,可以通过 ThingGatewayTransferManager.deviceTransferInfo(success:failure:) 来获取设备当前的迁移状态。当接口成功时,会返回网关迁移信息 info

如果 infostatusnonefinishfailed,表示没有在迁移中,此时可以进行迁移。否则,表示设备在迁移中。

class GatewayTransferController: UIViewController {

    func loadData() {
        SVProgressHUD.show()
        self.manager.deviceSupportsTransfer {[weak self] support in

            self?.manager.deviceTransferInfo(success: { info in
                if (info.status == .none || info.status == .finish || info.status == .failed) {
                    self?.label.text = "support"
                    SVProgressHUD.dismiss()
                }else{
                    self?.label.text = "device is transferring"
                    SVProgressHUD.dismiss()
                }
            }, failure: { e in
                self?.label.text = "support"
                SVProgressHUD.dismiss()
            })

        } failure: {[weak self] e in
            self?.label.text = "do not support"
            SVProgressHUD.dismiss()
        }
    }
}

获取网关列表

当设备不在迁移中时,通过 ThingGatewayTransferManager.gateways(success:failure:) 获取设备当前家庭下的网关列表,后续可以用当前设备来替换此网关列表中的任意网关。获取到的网关列表将存放到 ids 的数组中,方便后续渲染界面。

class GatewayTransferController: UIViewController {

    var ids: [String]?

    func loadData() {
        SVProgressHUD.show()
        self.manager.deviceSupportsTransfer {[weak self] support in

            self?.manager.deviceTransferInfo(success: { info in
                if (info.status == .none) {

                    self?.manager.gateways(success: { ids in
                        self?.ids = ids;
                        self?.label.text = "support"
                        SVProgressHUD.dismiss()

                    }, failure: { e in
                        self?.ids = nil;
                        self?.label.text = "support"
                        SVProgressHUD.dismiss()
                    })

                }else{
                    self?.label.text = "device is transferring"
                    SVProgressHUD.dismiss()
                }
            }, failure: { e in
                self?.label.text = "support"
                SVProgressHUD.dismiss()
            })

        } failure: {[weak self] e in
            self?.label.text = "do not support"
            SVProgressHUD.dismiss()
        }
    }
}

渲染界面

现在已经获取了需要被替换的网关列表,可以使用之前的 tableview 来展示处理。

extension GatewayTransferController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.ids != nil ? self.ids!.count : 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        ...
        cell?.textLabel?.text = self.ids![indexPath.row]
        return cell!
    }
}

替换网关

当用户单击 cell、选择某个网关 ID 的时候,可以通过 ThingGatewayTransferManager.transfer(fromGateway:success:failure:) 来将其替换掉。

extension GatewayTransferController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.transfer(self.ids![indexPath.row])
    }

    func transfer(_ id: String) {
        SVProgressHUD.show()
        self.manager.transfer(fromGateway: id) { ThingGatewayTransferInfo in

        } failure: { e in

        }
    }
}

监听结果

替换故障网关后,通过 ThingGatewayTransferManagerlistener 来通知替换结果。因此,还需要完成最后一步,注册 listener 并实现 ThingGatewayTransferManagerDelegate.transferManager(_:statusDidUpdate:) 方法。

class GatewayTransferController: UIViewController {

    override func viewDidLoad() {
        ...
        self.manager.addListener(self)
        ...
    }
}

extension GatewayTransferController: ThingGatewayTransferManagerDelegate {
    func transferManager(_ manager: ThingGatewayTransferManager, statusDidUpdate model: ThingGatewayTransferInfo) {
        if (model.status == .failed || model.status == .finish) {
            SVProgressHUD.dismiss()
            self.loadData()
        }
    }
}

Demo

至此,简单的 Demo 已经完成。更多信息,参考 Demo