Replace Faulty Gateway

Last Updated on : 2024-08-22 03:29:14download

Replace a gateway with the current gateway. For example, when a gateway fails, it can be quite cumbersome to migrate the devices connected to that gateway one by one to another gateway. With the replacement feature, users can complete the migration in one go.

Additionally, the groups, scenes, and automations can also be migrated to the new gateway.

Integration

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

target 'Your_Project_Name' do
    pod "ThingSmartBusinessExtensionKit"
end

Model

Gateway replacement status

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

Gateway replacement information

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 milliseconds when status changed.
    open var time: Double
}

Gateway replacement callback

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

Gateway replacement manager

open class ThingGatewayTransferManager : NSObject {
  ...
}

Gateway replacement management (class method)

Check support for replacing a faulty gateway

Before using the gateway replacement feature, check if the device supports it.

This is a class method. The instance method deviceSupportsTransfer(success:, failure:) serves the same purpose.

Request parameters Type Description
deviceId string The device ID.
success block The success callback.
failure block The failure callback.
/// 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)

Get gateway replacement information

Get the replacement status of the current gateway. Before a replacement, use this method to check if the gateway is currently undergoing a replacement operation.

This is a class method. The instance method deviceTransferInfo(success:, failure:) serves the same purpose.

Request parameters Type Description
deviceId string The device ID.
success block The success callback.
failure block The failure callback.
/// 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)

Get the list of alternative gateways

This is a class method. The instance method gateways(success:, failure:) serves the same purpose.

Request parameters Type Description
deviceId string The device ID.
success block The success callback.
failure block The failure callback.
/// 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)

Replace a gateway

Before replacing a gateway, check if the device supports gateway replacement and check if a replacement operation is currently in progress.

This is a class method. The instance method transfer(fromGateway:, success:, failure:) serves the same purpose.

Request parameters Type Description
from string The device ID of the old gateway.
to string The device ID of the new gateway.
success block The success callback.
failure block The failure callback.
/// 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)

Gateway replacement management (instance method)

Check support for replacing a faulty gateway

Before using the gateway replacement feature, check if the device supports it.

This is an instance method. The class method deviceSupportsTransfer(_:, success:, failure:) serves the same purpose.

Request parameters Type Description
success block The success callback.
failure block The failure callback.
/// 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)

Get gateway replacement information

Get the replacement status of the current gateway. Before a replacement, use this method to check if the gateway is currently undergoing a replacement operation.

This is an instance method. The class method deviceTransferInfo(deviceId:, success:, failure:) serves the same purpose.

Request parameters Type Description
success block The success callback.
failure block The failure callback.
/// 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)

Get the list of alternative gateways

This is an instance method. The class method gateways(deviceId:, success:, failure:) serves the same purpose.

Request parameters Type Description
success block The success callback.
failure block The failure callback.
/// 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)

Replace a gateway

Before replacing a gateway, check if the device supports gateway replacement and check if a replacement operation is currently in progress.

This is an instance method. The class method transfer(fromGateway:, toGateway:, success:, failure:) serves the same purpose.

Request parameters Type Description
gatewayId string The device ID of the old gateway.
success block The success callback.
failure block The failure callback.
/// 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)

Add a listener

Request parameters Type Description
listener ThingGatewayTransferManagerDelegate The listener.
/// Add a listener.
/// - Parameter listener: the listener which confirms ThingGatewayTransferManagerDelegate.
open func addListener(_ listener: ThingGatewayTransferManagerDelegate)

Remove a listener

Request parameters Type Description
listener ThingGatewayTransferManagerDelegate The listener.
/// Remove a listener.
/// - Parameter listener: the listener which confirms ThingGatewayTransferManagerDelegate.
open func removeListener(_ listener: ThingGatewayTransferManagerDelegate)

Examples

For more information, see 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

        }
    }

}

The following sections describe how to implement faulty gateway replacement.

Implement UI

Implement a simple UI.

  1. When the UI is initialized, pass in the deviceId as the device ID.

  2. The UI will display a UILabel and a UITableView. The UILabel has no text to display, and the UITableView has 1 sections and 0 rows. We will create a cell with the value1 style.

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

Load instance

Lazy load a manager instance of ThingGatewayTransferManager.

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

Check support for replacing a faulty gateway

Check if the device supports replacing a faulty gateway using ThingGatewayTransferManager.deviceSupportsTransfer(success:failure:).

  • If the device supports it, set the label text to support.
  • Otherwise, set the label text to do not support. The process ends here.
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()
        }
    }
}

Get migration status

If the device supports replacing a faulty gateway, you can get the current migration status using ThingGatewayTransferManager.deviceTransferInfo(success:failure:). The method returns the gateway migration info on success.

If info status is none, finish, or failed, it means there is no migration in progress, and you can proceed with the migration. Otherwise, the device is undergoing migration.

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

Get the list of gateways

If the device is not migrating, get the list of gateways in the current home using ThingGatewayTransferManager.gateways(success:failure:). You can replace any gateway from this list with the current device. Store the retrieved gateway list in the array of ids for later UI rendering.

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

Render UI

Use the tableview to display the list of gateways in the current home.

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

Replace gateway

When users tap a cell to select a gateway ID, replace the specified gateway using 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

        }
    }
}

Listen for results

Use the listener of ThingGatewayTransferManager to notify the result of the replacement. Register listener and implement 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

For more information, see Demo.